Svnman

From ProgClub
Revision as of 16:17, 23 March 2020 by John (talk | contribs) (Shell integration)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Svnman (pronounced ess-vee-en-man) is the ProgClub Subversion project administration software. That's the software that manages creation, maintenance, and release of Subversion projects. Svnman also supports recursive 'svn:externals' pinning with its freeze and unfreeze features. Svnman is primarily concerned with managing the version numbers for projects and releases thereof, and also the content of "branches", "tags", and "trunk" in your Subversion projects. For other projects see projects.

Contents

Status

We use semantic versioning. Latest production version: 1.0. Latest development version: 1.0.

See TODO for work that still needs to be done.

Motivation

Why this software? Basically to help with project administration of Subversion projects, particularly around versioning of artefacts.

Some particular pain points which resulted in the development of svnman were wanting to:

  1. have a sensible, robust, comprehensive, and well considered version numbering strategy which could be applied to all our projects
  2. have a managed PATCH version number which got incremented automatically upon each change to the project (for example prior to every Subversion check-in)
  3. support development on version branches to facilitate maintenance of older versions while newer versions are under development or in the pipeline
  4. keep 'trunk' tracking the latest stable release while doing development on version branches
    • and also to keep a bunch of standard 'tags' up-to-date
  5. have a standard project layout created for each new project
  6. manage multiple versions of multiple projects in multiple repositories, and have them integrate sensibly with each other
  7. have standard locations for project code generation, testing, and release scripts
  8. be able to freeze a project prior to (or during) release and then unfreeze it after
    • this enables a very agile practice whereby we can edit our dependencies in-place but release them safely too

Demonstration

Here we have a quick intro (3 A4 pages) and a more detailed walk through (6 A4 pages).

Quick intro

This quick intro demonstrates the value of svnman by taking you through some project administration basics. This intro has no prerequisites and all changes are done under the /tmp directory so you can follow along on your own computer (assuming you're running a sensible version of GNU/Linux, such as Ubuntu or Debian). To get set up:

$ sudo apt install php-cli subversion

Then get a copy of the code:

$ svn checkout https://www.progclub.org/svn/pcrepo/svnman/trunk /tmp/svnman

And create an alias for access:

$ alias svnman='/usr/bin/env php /tmp/svnman/bin/svnman.php'

Then create a demo repository for testing purposes:

$ svnadmin create /tmp/demorepo

You can then configure a 'demorepo' repository alias with the config subcommand. A repository alias allows you to refer to repository location, working base directory, and other settings, with an alias that has those details associated with it. For example to configure a 'demorepo' alias for our demo Subversion repository and working base directory:

$ svnman config --alias demorepo --location file:///tmp/demorepo --working-base /tmp

Note that the working base directory is the parent directory of our working copies. So we're just gonna put our working copies in /tmp for this demo.

Now you can create a new project named 'svnman-demo' in the 'demorepo' repository like this:

$ svnman create --repo demorepo --project svnman-demo

All new projects start at v0.1. A version branch of your new project has been checked out into a working copy at /tmp/svnman-demo-0.1, so go there:

$ cd /tmp/svnman-demo-0.1

The version branch is where software development is done. By default you will see that a bunch of default project files (and directories) have been created for you:

jj5@tact:/tmp/svnman-demo-0.1$ ls
bin  doc  etc  ext  inc  lib  src

We'll add a test file to our project and then release v0.1, like this:

jj5@tact:/tmp/svnman-demo-0.1$ echo demo > file.txt
jj5@tact:/tmp/svnman-demo-0.1$ svn add file.txt
jj5@tact:/tmp/svnman-demo-0.1$ svnman commit
jj5@tact:/tmp/svnman-demo-0.1$ svnman release

The output indicates that v0.1.4 has been released:

Latest...: file:///tmp/demorepo/svnman-demo/tags/latest/0.1
Major....: file:///tmp/demorepo/svnman-demo/tags/major/0
Minor....: file:///tmp/demorepo/svnman-demo/tags/minor/0/1
Release..: file:///tmp/demorepo/svnman-demo/tags/release/0/1/4
Trunk....: file:///tmp/demorepo/svnman-demo/trunk

So after our release our 'trunk' is now at version 0.1.4. You can confirm this by looking at the version file in trunk:

$ svn cat file:///tmp/demorepo/svnman-demo/trunk/inc/version.php
<?php

// the version numbers are managed by svnman...
define( 'SVNMAN_DEMO_VERSION_MAJOR', 0 );
define( 'SVNMAN_DEMO_VERSION_MINOR', 1 );
define( 'SVNMAN_DEMO_VERSION_PATCH', 4 );

// you can change the name but not the code...
define( 'SVNMAN_DEMO_NAME', 'svnman-demo' );
define( 'SVNMAN_DEMO_CODE', 'svnman-demo' );

// the following are automatically updated by Suybversion...
define(
  'SVNMAN_DEMO_SVN_DATE',
  '$Date: 2020-03-08 12:50:38 +1100 (Sun, 08 Mar 2020) $'
);
define( 'SVNMAN_DEMO_SVN_REVISION', '$Revision: 6 $' );
define( 'SVNMAN_DEMO_SVN_AUTHOR', '$Author: jj5 $' );

Let's checkout our trunk, like this:

$ svn co file:///tmp/demorepo/svnman-demo/trunk /tmp/svnman-demo-trunk

You can see our test file 'file.txt' is in trunk:

$ ls /tmp/svnman-demo-trunk
bin  doc  etc  ext  file.txt  inc  lib  src

Now let's bump our minor version and start v0.2 of our demo project:

jj5@tact:/tmp/svnman-demo-0.1$ svnman bump-minor

A version branch of your new project has been checked out into a working copy at '/tmp/svnman-demo-0.2', so go there:

$ cd /tmp/svnman-demo-0.2

Now for v0.2 let's remove file.txt then release:

jj5@tact:/tmp/svnman-demo-0.2$ svn rm file.txt
jj5@tact:/tmp/svnman-demo-0.2$ svnman commit
jj5@tact:/tmp/svnman-demo-0.2$ svnman release

Now let's go back to our trunk and get the latest version:

$ cd /tmp/svnman-demo-trunk
$ svn update
$ ls
bin  doc  etc  ext  inc  lib  src

You will see that 'file.txt' has been removed from trunk. But note that we didn't do any development on trunk. We did our development on the v0.1 version branch, then the v0.2 version branch, and trunk (and some tags and version numbers) were managed for us automatically by svnman. Managing the version numbers and the project in the Subversion repository is what svnman does!

So during this quick intro we created a 'demorepo' repository, then added a 'svnman-demo' project, and released two versions of our project, v0.1 and v0.2. You can see our effect with the list subcommand:

$ svnman list --repo demorepo
* svnman-demo: [0.1], [0.2]: file:///tmp/demorepo/svnman-demo/branches

And that concludes our quick intro. To clean up after yourself please run:

$ cd / && rm -rf /tmp/{demorepo,svnman*} && unalias svnman

If you like what you see you can install a permanent copy of svnman by following the instructions in the Installation Guide.

Walk through

This walk through demonstrates the value of svnman by taking you through the whole project administration life cycle from configuration to creation to maintenance to release to the next versions. This walk through has no prerequisites and all changes are done under the /tmp directory so you can follow along on your own computer (assuming you're running a sensible version of GNU/Linux, such as Ubuntu or Debian). To get set up:

$ sudo apt install php-cli subversion

Then get a copy of the code:

$ svn checkout https://www.progclub.org/svn/pcrepo/svnman/trunk /tmp/svnman

And create an alias for access:

$ alias svnman='/usr/bin/env php /tmp/svnman/bin/svnman.php'

Then create a demo repository for testing purposes:

$ svnadmin create /tmp/demorepo

You can then configure a 'demorepo' repository alias with the config subcommand. A repository alias allows you to refer to repository location, working base directory, and other settings, with an alias that has those details associated with it. For example to configure a 'demorepo' alias for our demo Subversion repository and working base directory:

jj5@tact:/tmp$ svnman config --alias demorepo --location file:///tmp/demorepo --working-base /tmp

Note that the working base directory is the parent directory of our working copies. So we're just gonna put our working copies in '/tmp' for this demo.

Now you can create a new project named 'svnman-demo' in the 'demorepo' repository like this:

jj5@tact:/tmp$ svnman create --repo demorepo --project svnman-demo

The output will be something like this:

/tmp/svnman-demo-0.1

which indicates that v0.1 (all new projects start at version 0.1) of your new project has been checked out into '/tmp/svnman-demo-0.1', so go there:

jj5@tact:/tmp$ cd /tmp/svnman-demo-0.1

Let's create a test program, like this:

jj5@tact:/tmp/svnman-demo-0.1$ echo $'#!/usr/bin/env php\n<?php echo "hello, world.\n";' > bin/hello.php
jj5@tact:/tmp/svnman-demo-0.1$ chmod +x bin/hello.php
jj5@tact:/tmp/svnman-demo-0.1$ svn add bin/hello.php

You can then commit with svnman. Committing with svnman ensures that code maintenance is run prior to checkin. Maintenance involves an optional code generation step and then the increment of the PATCH version number. By default the version numbers are in 'inc/version.php'. Run the following commands to see the SVNMAN_DEMO_VERSION_PATCH version incremented from 1 to 3:

jj5@tact:/tmp/svnman-demo-0.1$ cat inc/version.php
jj5@tact:/tmp/svnman-demo-0.1$ svnman commit -m 'Commit messages are optional.'
jj5@tact:/tmp/svnman-demo-0.1$ cat inc/version.php

If you're happy with v0.1 you can release it:

jj5@tact:/tmp/svnman-demo-0.1$ svnman release

The release process created the following tags in our Subversion repository (and also updated trunk):

Latest...: file:///tmp/demorepo/svnman-demo/tags/latest/0.1
Major....: file:///tmp/demorepo/svnman-demo/tags/major/0
Minor....: file:///tmp/demorepo/svnman-demo/tags/minor/0/1
Release..: file:///tmp/demorepo/svnman-demo/tags/release/0/1/4
Trunk....: file:///tmp/demorepo/svnman-demo/trunk

You can use svn ls to inspect, e.g.:

jj5@tact:/tmp/svnman-demo-0.1$ svn ls file:///tmp/demorepo/svnman-demo/trunk

You can see the version config file for your release here:

jj5@tact:/tmp/svnman-demo-0.1$ svn cat file:///tmp/demorepo/svnman-demo/trunk/inc/version.php

Note that for your production release in 'trunk' the SVNMAN_DEMO_VERSION_PATCH version is 4. Your development branch is at PATCH = 5, see:

jj5@tact:/tmp/svnman-demo-0.1$ cat inc/version.php

Maintaining that PATCH version number — and making sure it is regularly and consistently updated — is perhaps the main job of svnman. See the versioning section for details, but basically an even PATCH version is for a PROD (for "production") build, and an odd PATCH version is for a DEV (for "development") build. The release process makes sure the PATCH version number is properly incremented during each stage of a release.

So now that v0.1 is released, it's time to get ready for development of v0.2 with bump-minor. The bump-minor subcommand will increment the MINOR version number from 1 to 2:

jj5@tact:/tmp/svnman-demo-0.1$ svnman bump-minor

The output will be something like this:

/tmp/svnman-demo-0.2

which indicates that your new project version has been checked out into '/tmp/svnman-demo-0.2', so go there:

jj5@tact:/tmp/svnman-demo-0.1$ cd /tmp/svnman-demo-0.2

In order to test freezing/unfreezing of 'svn:externals' when we run our release (below) we need to set up an extra project we can use as a library:

jj5@tact:/tmp/svnman-demo-0.2$ svnman create --repo demorepo --project svnman-demo-lib

Now for v0.2 let's include our library project as an external project:

jj5@tact:/tmp/svnman-demo-0.2$ svn propset svn:externals "svnman-demo-lib file:///tmp/demorepo/svnman-demo-lib/branches/0.1" ext

And commit our changes:

jj5@tact:/tmp/svnman-demo-0.2$ svnman commit

Now if you do an `svn update` you will get a copy of svnman-demo-lib in the 'ext' dir:

jj5@tact:/tmp/svnman-demo-0.2$ svn update
jj5@tact:/tmp/svnman-demo-0.2$ ls ext/

Now let's change our program a little bit for v0.2:

jj5@tact:/tmp/svnman-demo-0.2$ echo $'#!/usr/bin/env php\n<?php echo "hello from v0.2!\n";' > bin/hello.php

And commit our changes:

jj5@tact:/tmp/svnman-demo-0.2$ svnman commit

So v0.2 looks fairly good, let's release it:

jj5@tact:/tmp/svnman-demo-0.2$ svnman release

As before the release process created a bunch of tags in our Subversion repository (and updated trunk):

Latest...: file:///tmp/demorepo/svnman-demo/tags/latest/0.2
Major....: file:///tmp/demorepo/svnman-demo/tags/major/0
Minor....: file:///tmp/demorepo/svnman-demo/tags/minor/0/2
Release..: file:///tmp/demorepo/svnman-demo/tags/release/0/2/12
Trunk....: file:///tmp/demorepo/svnman-demo/trunk

So we're done with v0.2, let's get ready for our v1.0 release with bump-major. The bump-major command will increment the MAJOR version number from 0 to 1:

jj5@tact:/tmp/svnman-demo-0.2$ svnman bump-major

The output will be something like this:

/tmp/svnman-demo-1.0

which indicates that your new project version has been checked out into '/tmp/svnman-demo-1.0', so go there:

jj5@tact:/tmp/svnman-demo-0.2$ cd /tmp/svnman-demo-1.0

Again we can modify our program for v1.0:

jj5@tact:/tmp/svnman-demo-1.0$ echo $'#!/usr/bin/env php\n<?php echo "hello from v1.0!\n";' > bin/hello.php

And commit:

jj5@tact:/tmp/svnman-demo-1.0$ svnman commit

And release:

jj5@tact:/tmp/svnman-demo-1.0$ svnman release

And now v1.0 is in production:

Latest...: file:///tmp/demorepo/svnman-demo/tags/latest/1.0
Major....: file:///tmp/demorepo/svnman-demo/tags/major/1
Minor....: file:///tmp/demorepo/svnman-demo/tags/minor/1/0
Release..: file:///tmp/demorepo/svnman-demo/tags/release/1/0/18
Trunk....: file:///tmp/demorepo/svnman-demo/trunk

You can look at the version file to see the MAJOR.MINOR.PATCH version numbers which are now at v1.0.19:

jj5@tact:/tmp/svnman-demo-1.0$ cat inc/version.php

Example output:

<?php

// the version numbers are managed by svnman...
define( 'SVNMAN_DEMO_VERSION_MAJOR', 1 );
define( 'SVNMAN_DEMO_VERSION_MINOR', 0 );
define( 'SVNMAN_DEMO_VERSION_PATCH', 19 );

// you can change the name but not the code...
define( 'SVNMAN_DEMO_NAME', 'svnman-demo' );
define( 'SVNMAN_DEMO_CODE', 'svnman-demo' );

// the following are automatically updated by Suybversion...
define(
  'SVNMAN_DEMO_SVN_DATE',
  '$Date: 2020-03-08 15:20:27 +1100 (Sun, 08 Mar 2020) $'
);
define( 'SVNMAN_DEMO_SVN_REVISION', '$Revision: 44 $' );
define( 'SVNMAN_DEMO_SVN_AUTHOR', '$Author: jj5 $' );

And have a look at the 'svn:externals' on the release tag for our v1.0 release:

jj5@tact:/tmp/svnman-demo-1.0$ svn propget svn:externals file:///tmp/demorepo/svnman-demo/tags/latest/1.0/ext

The output will be something like this:

svnman-demo-lib -r35 file:///tmp/demorepo/svnman-demo-lib/branches/0.1

Compare that with the development version from the 1.0 version branch:

jj5@tact:/tmp/svnman-demo-1.0$ svn propget svn:externals file:///tmp/demorepo/svnman-demo/branches/1.0/ext

The output will be something like this:

svnman-demo-lib file:///tmp/demorepo/svnman-demo-lib/branches/0.1

Notice that for the tagged release the 'svn:externals' have been "frozen" on revision 35 (-r35), whereas for the development version on the version branch the externals definition is not pinned to a specific revision but is tracking HEAD. That's a consequence of the freeze and unfreeze processes which happen automatically before and after a release. Freezing and unfreezing of 'svn:externals' before creating release tags is another main reason for using svnman.

So during this walk through we created a 'demorepo' repository, then added multiple versions of two projects ('svnman-demo' and 'svnman-demo-lib'). You can see our effect with the list subcommand:

$ svnman list --repo demorepo
* svnman-demo: [0.1], [0.2], [1.0]: file:///tmp/demorepo/svnman-demo/branches
* svnman-demo-lib: [0.1]: file:///tmp/demorepo/svnman-demo-lib/branches

And that concludes our walk through. To clean up after yourself please run:

$ cd ~ && rm -rf /tmp/demorepo /tmp/svnman* && unalias svnman

If you like what you see please see the Installation Guide for help with configuring svnman in production.

Administration

Contributors

Members who have contributed to this project. Newest on top.

All contributors have agreed to the terms of the Contributor License Agreement. This excludes any upstream contributors who tend to have different administrative frameworks.

Copyright

Copyright © 2020, Contributors.

License

Licensed under the MIT license.

Components

Libraries, tools, services or media from third parties used under license:

Resources

Downloads

There are presently no tarballs. Running an `svn checkout` against the ProgClub Subversion repository (pcrepo) is the recommended way to install this software. See the Installation Guide for details.

Source code

The source code can be browsed online:

The most interesting code is here:

The latest stable (read-only) released version of the code is available from Subversion here:

Or if you want the latest version for development purposes:

Note that our software development is done on the version branch, not on trunk. We use trunk to track the latest stable release.

Reference

The command reference contains a cheatsheet for frequently used commands. The repository command reference has a reference implementation for custom per-repository commands.

Command reference

Here are some basic notes on svnman commands which you might use frequently. Note that all of these commands rely on the 'inc/shell.sh' file being sourced in your shell. See shell configuration if you need help with that. Note that rarely will you invoke the `svnman` command directly, usually you will use one of these wrapper commands:

Command Notes Changes directory?
ss `svn update && svn status` no
sva `svn add --force --auto-props --parents --depth infinity .` no
sci `svnman sync` no
release `svnman release` (or bin/dev/release.sh) no
bump-minor `svnman bump-minor` yes
bump-major `svnman bump-major` yes
svnman-create `svnman create --repo $1 --project $2 ...` yes
svnman-list `svnman list --repo $1 ...` no
svnman-checkout `svnman checkout --repo $1 --project $2 ...` yes

Repository command reference

Here are some custom commands for use directly against the ProgClub Subversion repository, pcrepo:

Command Notes Changes directory?
pcrepo `pushd ~/repo/svn/pcrepo` yes
pcrepo-config `svnman config --alias pcrepo ...` no
pcrepo-create `svnman-create pcrepo "$@"` yes
pcrepo-list `svnman-list pcrepo "$@"` no
pcrepo-checkout `svnman-checkout pcrepo "$@"` yes

You are encouraged to use the 'pcrepo' reference implementation to create your own custom repository commands. You can find the reference implementation for the 'pcrepo' functions at the bottom of the 'inc/shell.sh' script.

Specifications

Functional specification

The functional specification describes what the project does.

svnman

The svnman software provides a system command called `svnman` which has various subcommands for administering projects in a Subversion repository.

The `svnman` command is usually established by creating a symlink somewhere in your $PATH to point at the 'bin/svnman.php' script that comes with the project source code. See the Installation Guide for information about how to set up an `svnman` command in your environment.

For details concerning the features available from the `svnman` command please see the command-line interface.

Subversion replacements

The svnman software augments some of your Subversion processes. In the large you can go on using Subversion like you used to, with e.g. `svn add`, `svn rm`, `svn diff`, etc. But there are a few `svn` subcommands that you should no longer use directly, instead you should use the corresponding/replacement svnman functionality instead. Those `svn` subcommands which are replaced are:

svn checkout

You can actually continue to use `svn checkout` directly, if you'd like; but there is an 'svnman-checkout' shell function which might make your life easier, as it automatically determines a project's latest version and will `cd` to your working copy on completion.

So svn checkout https://www.progclub.org/svn/pcrepo/svnman/branches/1.0/ svnman-1.0 && cd svnman-1.0 can be replaced with svnman-checkout pcrepo svnman.

svn status

You can still run `svn status` if you want, but we have a command, 'ss' (short for 'svn status'), which will do an `svn update` before an `svn status`. You can use 'ss' to make sure you're up to date and to check if you have any uncommitted changes.

So svn update && svn status can be replaced with ss.

svn commit

If you're working on a Subversion project that is managed by svnman then you probably shouldn't use `svn commit` (AKA `svn ci`) anymore.

The `svn commit` replacement is the command 'sci' (short for 'svn check-in') which you should call to commit changes in your working copy. (If you're not sure if you have changes, run 'ss'.)

If you are going to use `svn commit` directly (and you really shouldn't), please at least make sure that you call `svnman maint` before doing your commit.

Shell integration

The svnman software has been designed for maximal integration with your Unix shell, particularly BASH. We recommend adding the svnman aliases and shell functions to your .bashrc (or similar) — see the shell configuration section for details. These functions provide a simpler command-line interface to svnman and their output is used to change directory upon completion, which is quite handy.

Most of these aliases and shell functions are supposed to run with the current working directory pointing to a Subversion working copy.

So for example the PHPBOM project would have been created like this:

$ pcrepo-create phpbom

Note that these functions assume you have configured appropriate repository aliases (such as 'pcrepo') for use with the --repo argument.

The following aliases and shell functions (and some extra bonus stuff) are available for download from the svnman source, see the 'inc/shell.sh' script for details. You should source this script from your '.bashrc' file, or similar.

ss command

The 'ss' command is short for 'svn status'. It simply does an `svn update` followed by an `svn status`. We recommend you use 'ss' in place of 'svn status'. Running this command a lot is a good idea, because generally you want your working copy to be as fresh as it can be.

sva command

The 'sva' command is short for 'svn add'. It automatically flags all unversioned files for addition.

sci command

The 'sci' command is short for 'svn check-in'. It's a shortcut for `svnman sync`, which will make sure you're up to date and then commit changes, if any, after having run maintenance.

release command

The 'release' command is a shortcut for `svnman release`, or, alternatively, a custom project release script: 'bin/dev/release.sh'.

bump-minor command

The 'bump-minor' command is a shortcut for `svnman bump-minor'. It operates on the current working directory and will `cd` to the working copy of the new project version upon completion.

bump-major command

The 'bump-major' command is a shortcut for `svnman bump-major'. It operates on the current working directory and will `cd` to the working copy of the new project version upon completion.

svnman-create command

The 'svnman-create' command is a shortcut for `svnman create`. It's first argument is a repo alias and the second argument is a project name.

svnman-list command

The 'svnman-list' command is a shortcut for `svnman list`. It's first argument is a repo alias.

svnman-checkout command

The 'svnman-checkout' command is a shortcut for `svnman checkout`. It's first argument is a repo alias and the second argument is a project name.

Repository commands

It can be useful to create some custom shell functions to operate directly on your various repositories. Our 'inc/shell.sh' script has some example functions for pcrepo, being:

  • pcrepo
  • pcrepo-config
  • pcrepo-create
  • pcrepo-list
  • pcrepo-checkout

As a convenience you can create the analogous shell functions for your own repositories.

Technical specification

The technical specification describes how the project works.

The software is written in PHP (tested on version 7.2) and shells out to the `svn` command-line utility (tested on version 1.9.7).

Configuration data is kept in JSON format in '$HOME/.config/svnman/config.json'. Use the `svnman config` subcommand to specify configuration data via the command-line.

Versioning

The versioning article goes into more detail, but basically the version numbers supported by svnman are in the format MAJOR.MINOR.PATCH. Note that this versioning standard is used by both the svnman software itself and also any projects which use svnman as their project administration tool. This versioning standard is the only versioning standard supported by svnman at the present time.

Note that there can be multiple MAJOR.MINOR releases whereas a specific MAJOR.MINOR.PATCH release is unique. This means that you can continue issuing patches (such as security updates) to particular MAJOR.MINOR versions and releasing them while work is under way on newer versions. If you need a new MAJOR.MINOR version (say for your next prospective production release) then see the bump-minor subcommand for help with that. If you're getting ready for a new MAJOR version (which you should definitely consider if you're planning to introduce breaking changes) then see bump-major.

The versioning specification has support for extra version info, but that is not relevant to svnman, and svnman can be used with or without that extra information. Actually the introduction of the capabilities of svnman, particularly around management of the PATCH version number, have made some of that extra version information less important than it used to be (i.e. we don't need to lean on Subversion revision numbers to identify a version).

MAJOR

The MAJOR version number is the first number in a version and is incremented for breaking changes, except for version zero (0) and version one (1) which may be unstable.

MINOR

The MINOR version number is the second number in a version and is incremented for non-breaking changes for new supported versions. It starts at one (1) for MAJOR version zero (0), and at zero (0) for successive MAJOR versions. If you want to work on a new version of your project while having the capacity to maintain the previous version then you should bump the MINOR version prior to starting the new work.

PATCH

The PATCH version number is the third number in a version and is incremented prior to every commit (and release); the PATCH is odd for DEV builds and even for PROD builds. Note that not all PATCH versions get released.

Builds

Only two types of builds are supported by svnman: DEV and PROD. If you want to cut a BETA or Release Candidate (RC1, RC2, etc.) build, you can do that (see the versioning article for help on this topic), but it's best to use a DEV build for those, saving PROD for real live actual supported versions. When you run a release with the `svnman release` subcommand a PROD build is configured for release. After the production release the project is reconfigured as the next DEV build. So PROD builds only exist during a release, and before and after a release the project is for a DEV build. In this way all releases are releases to PROD, that's what 'release' means.

DEV

A 'DEV' (for "development") build is for a programmer or tester for testing and development purposes. You can use a DEV build in production if you want, but it might have known errors, change rapidly, or otherwise be unsupported. You can tell DEV builds by their odd PATCH version number (PATCH % 2 == 1). If you track the version branch you will typically see a DEV build, except for temporarily during an `svnman release`.

PROD

A 'PROD' (for "production") build is created by a project administrator (using the `svnman release` subcommand) when testing of the version branch is complete. You can tell PROD builds by their even PATCH version number (PATCH % 2 == 0). During a release PROD builds get tagged with their MAJOR.MINOR version number under 'tags/latest/' and also with their MAJOR/MINOR/PATCH version number under 'tags/release/'. Usually when the latest version branch is released to PROD we update 'trunk' to point at it. In this way 'trunk' usually tracks the latest stable production version, which might be different to what you're used to. If you track 'trunk' or 'tags' you should only ever see PROD builds, as DEV builds only happen on the version branch.

Repository layout

This section documents the layout of the project root and everything below it for projects stored in a Subversion repository.

Project root

The project root is a location in a Subversion repository named for the project. It can be the repository root, but is more usually a directory with a project name. For instance the project root for the svnman software in our pcrepo Subversion repository is:

The svnman software only supports project roots named after the project and stored directly within the repository. So if the project is called 'svnman' and the repository is 'https://www.progclub.org/pcrepo' then the project root is 'https://www.progclub.org/pcrepo/svnman'.

Topmost directories

When trying to figure out what to call everything I reviewed the svnbook, particularly the Recommended Repository Layout section. But that document simply referred to the subdirectories of the "topmost" directory, the "topmost" directory being the "project root". So I've just called the branches, tags, and trunk directories "topmost" directories, as that is where they are found. A name was needed for the --topmost argument, and also, I guess, for this documentation. So there is the project root (named after the project), then the "topmost directories", being branches, tags, and trunk, and then under those things start to vary based on the various types, the details follow.

So svnman presumes that the Subversion project has these "topmost" directories within the project root:

And that is fairly standard for a Subversion project. However, we don't use 'trunk' for development. Instead development happens in MAJOR.MINOR version branches.

When a version branch is released by svnman 'trunk' can optionally be updated. Within 'tags' the latest MAJOR.MINOR versions are maintained under 'tags/latest/MAJOR.MINOR' and releases are tagged under 'tags/release/MAJOR/MINOR/PATCH'. There are other types of tags too.

branches

So "branches" are a place for work in progress. Developers can spin up custom branches if they need, but generally work is done directly on a version branch. A version branch is a directory within "branches" named after the MAJOR.MINOR version as detailed below.

Version branches

Our software projects start with a version branch, being for version 0.1, and incrementing from there. All software development is generally done in a version branch. Version branches are project branches (under the "branches" directory in the Subversion repository) with a directory name in the format 'MAJOR.MINOR'. It's possible to have other sorts of branches (svnman will ignore those) but the branches that svnman does operate on must be version branches in the valid format.

So version 0.3 is developed in 'branches/0.3' and version 1.0 is developed in 'branches/1.0'.

For example the version branch for v1.0 of the svnman software is:

Or for a list of version branches see here:

Note that what we call "version branches" might also be called "release branches" by other people in other contexts. For us a "release" has different connotations so we talk about "version branches" not "release branches". Generally we don't use "feature branches", we do our work directly on a "version branch", and use feature flags when necessary.

tags

Once development on a version branch is stable, tested, and ready for release, the `svnman release` process is run. The release process creates and updates:

The astute reader will note that 'tags/minor' and 'tags/latest' are very similar, in that they both track MAJOR.MINOR versions, but in different ways. Both are supported and maintained, so which one you use is up to you. Having the two formats is useful for consistency with the 'tags/major' format but also the utility of having all MAJOR.MINOR releases available for review under 'tags/latest'.

tags/major

A 'tags/major' tag tracks the latest version for a MAJOR version number.

An example 'tags/major' for v1.x is here:

Following a MAJOR version tag instead of trunk is a solid choice. However, please note that per our versioning standard stability of MAJOR versions is not supported until version two (2).

tags/minor

A 'tags/minor' tag tracks the latest version for a MAJOR.MINOR version number.

An example 'tags/minor' for v1.0 is here:

tags/release

A 'tags/release' tag tracks a release for a MAJOR.MINOR.PATCH version number. Note that these tags are immutable. Unlike other tags the 'tags/release' tags are never altered after they have been created.

An example 'tags/release' for v1.0.1276 is here:

tags/latest

The 'tags/latest' tag tracks the latest version for a MAJOR.MINOR version number, but in a different format to 'tags/minor'.

An example 'tags/latest' for v1.0 is here:

Or for a list of released MAJOR.MINOR versions see here:

trunk

The absolute latest stable released version is always in trunk. Note that if older versions are maintained and released they won't override trunk. Trunk tracks the latest version of the latest release, and you can rely on 'trunk' to always have the latest released version. But be warned: if you follow 'trunk' you may get upgraded across MAJOR version numbers, which may have breaking changes. If that is of concern to you then you might prefer to track the MAJOR version in 'tags/major'.

An example 'trunk' is here:

Project layout

So when you create new projects with `svnman create` you get a bunch of boiler plate stuff automatically created for you. (And if you use one of the --phpbom arguments you get even more scaffolding.)

A typical initial project looks like this:

  • bin -- command-line programs
    • dev -- command-line programs for use in development
    • test -- command-line programs for testing
  • doc -- project documentation
    • gen -- automatically generated documentation
  • etc -- project configuration files
    • gen -- automatically generated configuration files
    • test -- configuration for testing
  • ext -- 'svn:externals' projects managed with freeze and unfreeze
  • inc -- include files
  • lib -- third-party libraries
  • src -- source code
    • code -- main source code
    • gen -- automatically generated source code
    • play -- programmer playground
    • test -- test code
    • tool -- tooling for build scripts etc.
    • web -- web content
      • controller -- front-controllers
      • res -- web assets such as styles, scripts, images, etc.
      • root -- web root files

bin

The 'bin' directory contains command-line programs provided with the project.

bin/dev

The 'bin/dev' directory contains command-line programs for use during software development.

bin/dev/gen.sh

The 'bin/dev/gen.sh' script is for project code generation. Compiling, compression, and minification are all things that can be done with this script. Code generation is done automatically during maintenance, but it's not a bad idea to run it again in 'bin/dev/release.sh' to make sure things are up-to-date prior to a release.

bin/dev/release.sh

The 'bin/dev/release.sh' script manages a release. By default this script just runs `svnman release` but if you need to do things before and after a release you should use this script to do those things.

bin/test

The 'bin/test' directory contains command-line programs for testing the project.

bin/test/test.sh

The 'bin/test/test.sh' script should run all tests for the project.

doc

The 'doc' directory contains project documentation.

doc/gen

The 'doc/gen' directory contains automatically generated documentation. Often code will be generated in MediaWiki format for inclusion on the project page. Documentation generation is usually done with the 'bin/dev/gen.sh' script.

etc

The 'etc' directory contains project configuration files.

etc/gen

The 'etc/gen' directory contains automatically generated configuration files. Config generation is usually done with the 'bin/dev/gen.sh' script.

etc/test

The 'etc/test' directory contains configuration files use for software testing.

ext

The 'ext' directory contains any 'svn:externals' projects that are managed with freeze, unfreeze, etc. See 'lib' for an alternative.

inc

The 'inc' directory contains include files.

inc/version.php

The 'inc/version.php' is the project version file for PHP projects. In future we may support other types of version file.

This version file is the file that gets updated with new MAJOR or MINOR or PATCH version information.

lib

The 'lib' directory contains third-party libraries used by the project. If these libraries are configured as 'svn:externals' (which is okay) they will *not* be managed by the freeze and unfreeze processes. See 'ext' for an alternative.

src

The 'src' directory contains most of the source code for a project.

src/code

The 'src/code' directory contains the main source code.

src/gen

The 'src/gen' directory contains automatically generated source code. Code generation is usually done with the 'bin/dev/gen.sh' script.

src/play

The 'src/play' directory is an area for programmers to try things out. This is for software testing purposes, but it is less formal than unit tests or integration tests etc. Programs under 'src/play' can be committed to source control but they are not run automatically during testing.

src/test

The 'src/test' directory is for unit tests and other code used during testing. See the 'bin/test/test.sh' for the main test runner.

src/tool

The 'src/tool' directory contains any tooling. Tooling is code used by code generation scripts such as 'bin/dev/gen.sh'.

src/web

The 'src/web' directory is for web content.

src/web/controller

The 'src/web/controller' directory is for front-controllers. Usually these are configured in Apache using the Alias directive to mount them at a particular URL.

src/web/res

The 'src/web/res' directory contains web assets such as styles, scripts, images, etc. This is for public web content.

src/web/root

The 'src/web/root' directory is for the content of the web root when/if this software is hosted on an entire domain. Typical files are 'favicon.ico' and 'robots.txt' etc.

Notes

Notes for implementers

If you are interested in incorporating this software into your project, here's what you need to know.

Installation

This software has been developed and tested on Ubuntu 18.04 LTS GNU/Linux. It will probably work in other Unix environments and it will definitely be broken on Windows. (If you'd like to make it work on Windows we will accept your patch!)

After you install dependencies you need to decide if you want to install for just your user or for an entire system.

Dependency installation

In order to run svnman you might also need to install some dependencies, if so do that first:

$ sudo apt install php-cli subversion

System installation

After you install dependencies you can install svnman for an entire system with these two commands:

$ sudo svn checkout https://www.progclub.org/svn/pcrepo/svnman/trunk /usr/local/lib/svnman
$ sudo ln -s /usr/local/lib/svnman/bin/svnman.php /usr/local/bin/svnman

Then see the shell configuration and repository configuration sections for final touches.

System upgrade

If you've done a system installation you can do a system upgrade like this:

$ sudo svn update /usr/local/lib/svnman

User installation

First make sure you've installed the dependencies.

The recommended way to install this software is by checking out the 'trunk' version from source control.

In order to run svnman you should create an 'svnman' symlink somewhere in your $PATH and point it to 'bin/svnman.php'.

So a full installation might look something like this:

$ cd ~/software
$ svn checkout https://www.progclub.org/svn/pcrepo/svnman/trunk svnman
$ cd ~/bin
$ ln -s ~/software/svnman/bin/svnman.php svnman

Then see the shell configuration and repository configuration sections for final touches.

User upgrade

Assuming you followed the user installation instructions you can do a user upgrade something like this:

$ svn update ~/software/svnman

Shell configuration

So the way to configure your shell for the best svnman experience is to edit your ~/.bashrc file and add a line to include the aliases and shell functions from the 'inc/shell.sh' script.

If you did a system installation your source line for your ~/.bashrc file will look like this:

source /usr/local/lib/svnman/inc/shell.sh

If you did a user installation your source line for your ~/.bashrc file will look something like this:

source ~/software/svnman/inc/shell.sh

So basically you need to source 'inc/shell.sh' from wherever you've stowed the svnman software.

Repository configuration

After you install svnman you might like to configure one or more repository aliases using the config subcommand.

For example the config for 'pcrepo' might be something like this:

$ svnman config \
   --alias         pcrepo \
   --location      https://www.progclub.org/svn/pcrepo \
   --working-base  ~/repo/svn/pcrepo \
   --viewvc        https://www.progclub.org/pcrepo

Notes for developers

If you're looking to set up a development environment for this project, here's what you need to know.

Get the latest code from the version branch:

$ svn checkout https://www.progclub.org/svn/pcrepo/svnman/branches/1.0 svnman-1.0

You can then run the unit tests like this:

$ cd svnman-1.0 && bin/test/test.sh

Note that you may need to install some dependencies, such as:

# apt install php-cli subversion

If you have a bugfix or improvement please send your patch to jj5@progclub.org along with a statement that you are willing to be listed in the contributors section of the documentation and that you agree to the terms of the Contributor License Agreement.

Notes for administrators

To release a version of this project use the software itself.

First, run maintenance and commit any changes:

$ svnman commit

Then run the release:

$ bin/dev/release.sh

You will be prompted to update the project documentation.

Miscellanea

Subversion

The svnman software makes use of the Subversion command-line interface, being the `svn` command. If Subversion is not installed then svnman won't work! You will need to know the basics of Subversion to be productive with svnman, if you need to learn the `svn` command-line the svnbook is your one stop shop. See the Subversion replacements section for notes about which `svn` subcommands you should avoid while you're using svnman for project administration.

Revisions

The Subversion software allocates a 'revision number' to each commit. The revision number starts at one (1) and increments for each successive commit. You can often use a Subversion revision number to request content that was current at the time a specific revision was made. We use revision numbers in the freeze process.

HEAD

When talking about Subversion revisions the term 'HEAD' is used to refer to the latest revision, whatever that happens to be at the time.

svn:externals

The Subversion software allows for named properties to be set on files/directories that are under source control. Some of these properties are special Subversion properties which have special meaning. One such property is the 'svn:externals' property.

The 'svn:externals' property allows for external Subversion projects to be configured as dependencies of the current project. This allows for your Subversion project to use other Subversion projects which will get loaded from their sources automatically during `svn checkout` or `svn update`. Our svnman software has special support for 'svn:externals' via our freeze and unfreeze processes (both of which happen automatically during a release).

The 'svn:externals' specification format allows for the optional specification of a repository revision number to 'pin' an external project at a specific revision. When pinned an 'svn:externals' definition will always checkout the same version of the external dependency, as indicated by the revision number specified in the pinning. When unpinned the HEAD revision of the external dependency will be used (during checkout and update etc).

As an example you can see an 'svn:externals' definition on one of my projects, jj5-bin:

Look down the bottom of the page for the above URL and you will see the 'svn:externals' property and its configuration, like this:

bugslist  https://www.progclub.org/svn/pcrepo/bugslist/branches/0.2
svnman    https://www.progclub.org/svn/pcrepo/svnman/branches/1.0

This configuration causes the 'bugslist' and 'svnman' software to be included as an external project for the 'jj5-bin' software. The 'svn:externals' definition from the above is on the version branch and therefore has no revision number specified and thus, being unpinned, tracks HEAD. However a released version of jj5-bin will be pinned, see for example:

Look down the bottom of the page for the above URL and you will see the 'svn:externals' property has been configured to point to a specific revision number of -r7622:

bugslist  -r7622  https://www.progclub.org/svn/pcrepo/bugslist/branches/0.2
svnman    -r7622  https://www.progclub.org/svn/pcrepo/svnman/branches/1.0

All in all 'svn:externals' is a very important Subversion feature which enables much of the functionality of svnman.

Pinning

So 'pinning' is an optional feature of 'svn:externals'. An 'svn:externals' definition can be "unpinned", in which case the HEAD revision is used, for example:

svnman    https://www.progclub.org/svn/pcrepo/svnman/branches/1.0
bugslist  https://www.progclub.org/svn/pcrepo/bugslist/branches/0.2

Or it can be "pinned", in which case the indicated revision is used, for example:

svnman    -r7622  https://www.progclub.org/svn/pcrepo/svnman/branches/1.0
bugslist  -r7622  https://www.progclub.org/svn/pcrepo/bugslist/branches/0.2

So with the above 'pinned' libraries revision 7622 (-r7622) will be used when they are checked out, not the HEAD revision.

Note that the freeze process will recursively pin 'svn:externals' on 'ext' directories, but 'svn:externals' can be pinned by processes other than freeze; particularly with the --pin-externals option used with `svn cp` during tagging operations, or manually, with `svn propedit`.

Feature flags

A feature flag is a software setting that enables (or disables) a particular feature. The idea is that you can do new feature development with the feature disabled in production, and then enable the feature in production when it is ready. This can avoid the need for "feature branches" and allow programmers to coordinate their changes within a shared version branch. See What is a “feature flag”? for more information.

ViewVC

The ViewVC software can be used for browsing a Subversion repository via the web. We intend to support ViewVC integration, but, ah, that isn't done yet...

BASH

The bash shell is our Unix shell of choice. You don't need Bash to run svnman but it is used by our build scripts.

PHP

The svnman software is written mostly in the PHP programming language which we^H^HI love! :)

Other bits and pieces are done with JSON, Subversion, and BASH.

Ubuntu

This software was developed and tested on Ubuntu 18.04 LTS.

JSON

We use the JavaScript Object Notation format for our configuration data.

$PATH

When you install svnman you should make sure a symlink to 'bin/svnman.php' is in your $PATH environment variable.

$HOME

We rely on the $HOME environment variable being set to indicate your home directory. We need to know where your home directory is so that we can save and load your configuration data (see config).

PHPBOM

Our svnman utility has first-class support for our PHPBOM library. Basically when you use svnman to create a new project you can optionally have the PHPBOM library automatically included in your project.

VERSION

Supported version numbers are in the format MAJOR.MINOR.PATCH. See versioning for more info.

NOTE

We often put notes in our code. The format is something like this:

// {date} {user} - NOTE: {note}

Where {date} is in ISO 8601 format (yyyy-mm-dd) and the {user} is the username of the person who left the note. A {note} is just some text that aims to be helpful and usually relates to some code that follows the note itself.

We also use a similar format for TODO items etc. These formats are supported by bugslist which we use to generate documentation.

AKA

The acronym "AKA" stands for "Also Known As".

Generated documentation

The following documentation is automatically generated from the code.

Command-line interface

general usage: svnman SUBCOMMAND [ARG...] [DIR...]
A Subversion project management tool.
Type `svnman help <subcommand>` for help on a specific subcommand.
Type `svnman version` to see the program version.
Type `svnman errors` to see information about possible program errors.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

SUBCOMMAND

Available subcommands:

Arguments

Available arguments:

--quiet

-q [--quiet] .........: suppress error/warning/debug output

--debug

--debug ..............: output extra info for debugging

--alias

--alias ALIAS ........: name of a repository alias; see the 'config'
                        subcommand for more information

--location

--location URL .......: location of the repository

--working-base

--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.

--working-copy

--working-copy DIR ...: directory containing the working copy; if
                        unspecified the working copy will go under
                        --working-base in a directory calculated using the
                        --project and the MAJOR.MINOR version such as e.g.
                        svnman-1.0

--viewvc

--viewvc URL .........: ViewVC URL for the repository; see the 'browse'
                        subcommand for notes on how this setting is used

--repo

--repo ALIAS|URL .....: Subversion repository to operate on; note that if
                        you nominate an ALIAS then other options (such as
                        --working-base etc) can be inferred from your config
                        file

--project

--project NAME .......: name of the project; this will be used in the
                        repository as the project name and also as part of
                        the working copy path (if --working-copy is
                        unspecified)

--project-code

--project-code CODE ..: project code (lowercase); generated from --project
                        if unspecified

--project-const

--project-const CONST : project const (uppercase); generated from
                        --project-code if unspecified

--no-checkout

--no-checkout ........: don't checkout into working copy

--checkout

--checkout ...........: checkout into working copy [default]

--no-trunk

--no-trunk ...........: trunk is not updated

--trunk

--trunk ..............: trunk is updated

--auto-trunk

--auto-trunk .........: trunk updated if project is on latest version branch
                        [default]

--no-phpbom

--no-phpbom ..........: don't configure the PHPBOM library [default]

--phpbom

--phpbom .............: configure svn:externals on 'lib' DIR for latest
                        PHPBOM release; when using the PHPBOM library some
                        extra files are automatically generated too

--phpbom-dev

--phpbom-dev .........: configure svn:externals on 'ext' DIR for development
                        PHPBOM library; when using the PHPBOM library some
                        extra files are automatically generated too

--no-netbeans

--no-netbeans ........: don't create a NetBeans project [default]

--netbeans

--netbeans ...........: create a NetBeans project in the working copy

--topmost

--topmost DIR ........: the 'topmost' directory within the project root. Is
                        typically one of "branches", "tags/latest", "trunk",
                        etc. The default value is "branches"

--version

--version DIR ........: the path to the version (within --topmost). May be a
                        version number in the form X.Y or in the form X/Y/Z
                        etc. If unspecified the latest version will be used

--message

-m [--message] STRING : `svn commit` message; the commit message is always
                        optional; we recommend not using it, but that is a
                        matter for you

Argument formats

ARG

An argument is a name prefixed with two dashes, optionally followed by whitespace and a value, depending on the argument. For example:

--no-trunk

Or:

--repo pcrepo

The special arguemnt '--' indicates that all subsequent command-line values are to be treaded as DIRs not as ARGs.

Note that some arguments also support a shorter version, which is usually a dash followed by a single letter. For example --message can be abbreviated as -m.

DIR

A PATH to a directory in the local file system. Absolute and relative paths are supported for input, but if directory paths are stored (such as with working base directories in repository aliases) the absolute paths are computed and stored at the time of configuration not at time of later use.

Note that if no DIRs are provided the current working directory is processed.

PATH

A location in the local file system. Absolute or relative paths are supported. A path can be to a standard file, directory, symlink, etc. Generally if a directory is required we explicitly document it as a DIR. If your PATH is to the wrong type of file per your SUBCOMMAND/ARG then you can expect to see an error as a result.

URL

A Uniform Resource Locator, typically with a scheme such as:

  • http:
  • https:
  • file:
  • svn:

NAME

Name format:

/^[a-z][a-z0-9\._-]{0,42}[a-z0-9]$/

CODE

Code format:

/^[a-z][a-z0-9-]{0,14}[a-z0-9]$/

CONST

Const format:

/^[A-Z][A-Z0-9_]{0,14}[A-Z0-9]$/

ALIAS

Alias format:

/^[a-z][a-z0-9-]{0,14}[a-z0-9]$/

STRING

String format:

/^[^\x00-\x09\x0b\x0c\x0e-\x1f\x7f]*$/

Subcommands

config

config: usage: svnman config ARG...

Configure an svnman repository alias.

A repository alias associates an alias with a repo location, allowing the repo alias to be used as a shortcut for the repo location in commands which accept a --repo argument. A default working base DIR and a ViewVC URL can also be associated with a repo alias.

Note that the config file is in JSON format in:

$HOME/.config/svnman/config.json

If your alias is not already configured then --location is required. If it is already configured the existing location will be retained if a new location is not nominated. If you want to clear an optional setting you can set it to the empty string ().

Example usage:

svnman config \
 --alias         pcrepo \
 --location      https://www.progclub.org/svn/pcrepo \
 --working-base  ~/repo/svn/pcrepo \
 --viewvc        https://www.progclub.org/pcrepo

Required arguments:

--alias ALIAS ........: name of a repository alias; see the 'config'
                        subcommand for more information

Optional arguments:

--location URL .......: location of the repository
--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.
--viewvc URL .........: ViewVC URL for the repository; see the 'browse'
                        subcommand for notes on how this setting is used

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

settings

settings: usage: svnman settings [ARG...] [DIR...]

Report on an svnman repository alias and its settings.

See the 'config' subcommand for configuring the data reported by 'settings'. If the --alias setting is not specified we try to find the appropriate setting based on the current working directory or DIR if specified.

Example usage:

svnman settings --alias pcrepo

Optional arguments:

--alias ALIAS ........: name of a repository alias; see the 'config'
                        subcommand for more information

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

info

info: usage: svnman info [DIR...]

Report Subversion info and version information for an svnman project in DIR.

Version information includes:

  • path of the version file
  • whether the version file exists or not
  • project MAJOR.MINOR.PATCH version number (if version file exists)
  • build type (if version file exists)

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

create

create: usage: svnman create ARG...

Create a new project in a Subversion repository.

New projects are created with:

MAJOR version = 0
MINOR version = 1
PATCH version = 1

The odd PATCH version indicates that the initial version is a DEV version.

So basically a new project is just a couple of standard directories in the repository along with an initial version file. Also, if you've included the PHPBOM library, the svn:externals for that will be configured too.

Depending on your command-line options the initial 'branches/0.1' version will be checked out into a working copy for you.

Example usage:

svnman create --repo pcrepo --project my-killer-app

Required arguments:

--repo ALIAS|URL .....: Subversion repository to operate on; note that if
                        you nominate an ALIAS then other options (such as
                        --working-base etc) can be inferred from your config
                        file
--project NAME .......: name of the project; this will be used in the
                        repository as the project name and also as part of
                        the working copy path (if --working-copy is
                        unspecified)

Optional arguments:

--project-code CODE ..: project code (lowercase); generated from --project
                        if unspecified
--project-const CONST : project const (uppercase); generated from
                        --project-code if unspecified
--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.
--working-copy DIR ...: directory containing the working copy; if
                        unspecified the working copy will go under
                        --working-base in a directory calculated using the
                        --project and the MAJOR.MINOR version such as e.g.
                        svnman-1.0
--no-checkout ........: don't checkout into working copy
--checkout ...........: checkout into working copy [default]
--no-phpbom ..........: don't configure the PHPBOM library [default]
--phpbom .............: configure svn:externals on 'lib' DIR for latest
                        PHPBOM release; when using the PHPBOM library some
                        extra files are automatically generated too
--phpbom-dev .........: configure svn:externals on 'ext' DIR for development
                        PHPBOM library; when using the PHPBOM library some
                        extra files are automatically generated too
--no-netbeans ........: don't create a NetBeans project [default]
--netbeans ...........: create a NetBeans project in the working copy

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

list

list: usage: svnman list [ARG...]

List projects in a Subversion repository, or if no repository nominated lists available repositories from the config file.

In the output project names are prefixed with '^' if the project is in a nonstandard format.

For a project listing available versions are listed. If an available version is in square brackets this indicates that the version is available on the local machine in the standard location for a working copy.

Example usage:

svnman list --repo pcrepo --topmost tags/latest

Optional arguments:

--repo ALIAS|URL .....: Subversion repository to operate on; note that if
                        you nominate an ALIAS then other options (such as
                        --working-base etc) can be inferred from your config
                        file
--topmost DIR ........: the 'topmost' directory within the project root. Is
                        typically one of "branches", "tags/latest", "trunk",
                        etc. The default value is "branches"

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

checkout

checkout: usage: svnman checkout ARG...

Checkout an existing project from a Subversion repository.

Example usage:

svnman checkout --repo pcrepo --project my-killer-app --version 0.2

Required arguments:

--repo ALIAS|URL .....: Subversion repository to operate on; note that if
                        you nominate an ALIAS then other options (such as
                        --working-base etc) can be inferred from your config
                        file
--project NAME .......: name of the project; this will be used in the
                        repository as the project name and also as part of
                        the working copy path (if --working-copy is
                        unspecified)

Optional arguments:

--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.
--working-copy DIR ...: directory containing the working copy; if
                        unspecified the working copy will go under
                        --working-base in a directory calculated using the
                        --project and the MAJOR.MINOR version such as e.g.
                        svnman-1.0
--no-netbeans ........: don't create a NetBeans project [default]
--netbeans ...........: create a NetBeans project in the working copy
--topmost DIR ........: the 'topmost' directory within the project root. Is
                        typically one of "branches", "tags/latest", "trunk",
                        etc. The default value is "branches"
--version DIR ........: the path to the version (within --topmost). May be a
                        version number in the form X.Y or in the form X/Y/Z
                        etc. If unspecified the latest version will be used

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

sync

sync: usage: svnman sync [ARG...] [DIR...]

Synchronize working copy in DIR.

The synchronization process is basically:

  1. svn up
  2. svnman commit
  3. svn status

Optional arguments:

-m [--message] STRING : `svn commit` message; the commit message is always
                        optional; we recommend not using it, but that is a
                        matter for you

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

commit

commit: usage: svnman commit|ci [ARG...] [DIR...]

Run maintenance on DIR then commit.

See `svnman help maint` for information concerning the maintenance process. After maintenance (assuming it is successful) an `svn commit` is performed.

Note that if you are running `svn commit` (AKA: `svn ci`) directly then you should make sure you call `svnman maint` to run maintenance *before* an actual commit. If you don't do this the PATCH version number will not be incremented properly. If you absolutely must run `svn commit` directly then make sure you have incremented the PATCH version by two (to an ODD number) in the version file for your project prior to commit. Run `svnman info` if you need to know which file is being used for version info in your current working directory.

Optional arguments:

-m [--message] STRING : `svn commit` message; the commit message is always
                        optional; we recommend not using it, but that is a
                        matter for you

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

maint

maint: usage: svnman maint [DIR...]

Run maintenance on DIR.

Maintenance includes optional code generation and updating of the PATCH version. You should run this before your commits. You can only run maintenance on DEV builds and this is enforced by this subcommand. If your working copy is for a PROD build (i.e. has an even PATCH version number) then you may need to run `svnman fix-version` to remedy the situation.

For the code generation the file 'bin/dev/gen.sh' is executed, if it exists and is executable.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

freeze

freeze: usage: svnman freeze [DIR...]

Freeze external subprojects in DIR.

Only available for projects that are in 'branches'. When frozen svn:externals under the 'ext' directory are pinned to the revision which was current at the time of freezing.

Note that the 'freeze' process is recursive.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

unfreeze

unfreeze: usage: svnman unfreeze|thaw [DIR...]

Unfreeze external subprojects in DIR.

Only available for projects that are in 'branches'. When unfrozen svn:externals under the 'ext' directory are unpinned from a specific revision.

Note that the 'unfreeze' process is recursive.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

release

release: usage: svnman release [ARG...] [DIR...]

Release a project in DIR.

Prior to release projects are frozen, and after release they are unfrozen. When a release is done the starting version must be a DEV build (with an odd PATCH version number), then during the release the PATCH version number will be incremented to an even version number for the release, and after the release the PATCH version number will be incremented again to a new odd version number for use by the next DEV build.

So the release process is roughly:

  1. freeze
  2. bump PATCH to next PROD version
  3. commit
  4. create tags
  5. optionally update trunk
  6. unfreeze
  7. bump PATCH to next DEV version
  8. commit

Optional arguments:

--no-trunk ...........: trunk is not updated
--trunk ..............: trunk is updated
--auto-trunk .........: trunk updated if project is on latest version branch
                        [default]

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

bump-minor

bump-minor: usage: svnman bump-minor [DIR...]

Create a new version branch from DIR, incrementing the MINOR version number.

Note that during a MINOR version bump the PATCH version is preserved. This means that across MAJOR.MINOR versions PATCH version numbers will duplicate and diverge. This is by design. One consequence of this is that the PATCH number indicates, for every MAJOR.MINOR version, pretty much exactly how many commits have been made in that version's entire history.

Note also that the MINOR version number will be updated in both the URL for the branch and in the project version file (so that's in two places).

Optional arguments:

--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.
--working-copy DIR ...: directory containing the working copy; if
                        unspecified the working copy will go under
                        --working-base in a directory calculated using the
                        --project and the MAJOR.MINOR version such as e.g.
                        svnman-1.0
--no-checkout ........: don't checkout into working copy
--checkout ...........: checkout into working copy [default]

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

bump-major

bump-major: usage: svnman bump-major [DIR...]

Create a new version branch from DIR, incrementing the MAJOR version number (and resetting the MINOR version number to zero).

Note that during a MAJOR version bump the PATCH version is preserved. This means that across MAJOR.MINOR versions PATCH version numbers will duplicate and diverge. This is by design. One consequence of this is that the PATCH number indicates, for every MAJOR.MINOR version, pretty much exactly how many commits have been made in that version's entire history.

Note also that the MAJOR version number will be updated in both the URL for the branch and in the project version file (so that's in two places).

Optional arguments:

--working-base DIR ...: parent directory of the working copy; if unspecified
                        it is loaded from the config file (if possible); if
                        unspecified and not configured then checkout options
                        that depend on this setting will be skipped.
--working-copy DIR ...: directory containing the working copy; if
                        unspecified the working copy will go under
                        --working-base in a directory calculated using the
                        --project and the MAJOR.MINOR version such as e.g.
                        svnman-1.0
--no-checkout ........: don't checkout into working copy
--checkout ...........: checkout into working copy [default]

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

browse

browse: usage: svnman browse

Open current directory in ViewVC in web browser.

This requires ViewVC to be configured via the 'config' subcommand.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

netbeans

netbeans: usage: svnman netbeans

Creates a NetBeans project in the current directory.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

gen-doc

gen-doc: usage: svnman gen-doc

Generates svnman documentation for use in the project wiki.

You can find said documentation here:

Have a look in the 'bin/dev/gen.sh' script to see how documentation generation is done.

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

gen-vars

gen-vars: usage: svnman gen-vars

Generates shell config containing error constants definitions.

You can `source` the output of this command to configure your environment with error info:

`source <(svnman gen-vars)`

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

fix-version

fix-version: usage: svnman fix-version [DIR...]

If the PATCH version number is left on an even value (perhaps due to a failure during `svnman release`) then this subcommand will bump it to the next odd value, making it a valid development PATCH version number again. If the PATCH version number is already an odd value this subcommand does nothing and fails indicating error.

For more info on our version numbers see:

Global arguments:

-q [--quiet] .........: suppress error/warning/debug output
--debug ..............: output extra info for debugging

For help on argument formats see `svnman help`.

Errors

Potential svnman error levels and their meaning:

Error level Error name Error text Hint
0 ERR_SUCCESS program completed successfully.
10 ERR_HELP help (or version/error info) requested.
11 ERR_PHP_ERROR PHP error. please let the maintainer know: John Elliot V <jj5@progclub.org>
12 ERR_PHP_EXCEPTION unhandled exception. please let the maintainer know: John Elliot V <jj5@progclub.org>
13 ERR_PHP_ASSERT assertion failed. please let the maintainer know: John Elliot V <jj5@progclub.org>
14 ERR_NO_ASSERTIONS "zend.assertions" are not enabled. enable "zend.assertions" in php.ini.
15 ERR_NOT_IMPLEMENTED functionality not implemented.
16 ERR_NOT_SUPPORTED situation not supported. please let the maintainer know: John Elliot V <jj5@progclub.org>
17 ERR_NOT_A_DIRECTORY not a directory.
18 ERR_NOT_A_DEV_BUILD not a DEV build. this is a PROD build. For a DEV build increment the PATCH by 1. Try `svnman fix-version`.
19 ERR_INVALID_PATH invalid path.
20 ERR_INVALID_BRANCH_VERSION invalid branch version. make sure VERSION in branches/VERSION is in format MAJOR.MINOR.
21 ERR_INVALID_VERSION version discrepancy. check the branches/VERSION is same as MAJOR/MINOR from version file.
22 ERR_INVALID_VERSION_PART invalid version part.
23 ERR_INVALID_VERSION_FORMAT version is in an invalid format. check you've used '.' or '/' as appropriate to your context.
24 ERR_INVALID_VERSION_NUMBER version contains an invalid version number. can't be 0.0 or 1.0.0 or 1.1.123.456 etc.
25 ERR_INVALID_WORKING_BASE invalid working base.
26 ERR_INVALID_EXTERNALS invalid svn:externals.
27 ERR_INVALID_EXTERNALS_DIR invalid svn:externals directory. the directory should come first.
28 ERR_INVALID_NAME invalid name.
29 ERR_INVALID_CODE invalid code.
30 ERR_INVALID_CONST invalid const.
31 ERR_INVALID_ALIAS invalid repository alias.
32 ERR_INVALID_STRING invalid string.
33 ERR_INVALID_VERSION_PATCH invalid version PATCH.
34 ERR_INVALID_CONFIG invalid config. your config file is corrupt, consider deleting it or revise.
35 ERR_MISSING_HOME_ENV_VAR missing $HOME environment variable. review your shell configuration such as .bashrc.
36 ERR_MISSING_ARG_VALUE missing argument value.
37 ERR_MISSING_ALIAS missing --alias.
38 ERR_MISSING_LOCATION missing --location.
39 ERR_MISSING_HOME_DIR missing $HOME directory.
40 ERR_MISSING_VERSION_FILE missing version file.
41 ERR_MISSING_VERSION_PART missing version part.
42 ERR_MISSING_PROJECT_NAME missing project name.
43 ERR_NO_SUCH_ALIAS no such --alias.
44 ERR_NO_BROWSER could not find a web browser.
45 ERR_NO_VIEWVC_URL could not compute ViewVC URL.
46 ERR_NO_CONFIG no config. run `svnman config` and nominate repository settings.
47 ERR_NO_CONFIG_LOCATION no location config. run `svnman config` and nominate a --location setting.
48 ERR_NO_CONFIG_VIEWVC no ViewVC config. run `svnman config` and nominate a --viewvc setting.
49 ERR_VERSION_CONFLICT_MAJOR MAJOR version conflict. check the branches/VERSION indicates same as MAJOR in version file.
50 ERR_VERSION_CONFLICT_MINOR MINOR version conflict. check the branches/VERSION indicates same as MINOR in version file.
51 ERR_PATCH_VERSION_EVEN PATCH version is even (PROD). consider running `svnman fix-version` to resolve.
52 ERR_PATCH_VERSION_ODD PATCH version is odd (DEV). if PATCH version is odd there's no need to run `svnman fix-version`.
53 ERR_EXPECTED_BRANCHES expected "branches".
54 ERR_MKDIR_FAILED mkdir failed.
55 ERR_CHDIR_FAILED chdir failed.
56 ERR_NO_EXTERNALS no externals.
57 ERR_NOT_WORKING_COPY not an svn working copy.
58 ERR_CANNOT_MAKE_TEMP_DIR cannot make temp dir.
59 ERR_CANNOT_MATCH_VERSION_PATCH cannot match version PATCH.
60 ERR_SVN_MISSING no executable `svn` command. make sure Subversion is installed. e.g. `apt install subversion`.
61 ERR_SVN_COMMAND_FAILED svn command failed.
62 ERR_SVN_CANNOT_ACCESS cannot access svn repository.
63 ERR_SVN_INVALID_INFO unsupported `svn info` output. please let the maintainer know: John Elliot V <jj5@progclub.org>
64 ERR_SVN_HAS_CHANGES found uncommitted changes.
65 ERR_SVN_BRANCH_EXISTS branch already exists.
66 ERR_FILE_WRITE error writing file.
67 ERR_FILE_CLOSE error closing file.
68 ERR_FILE_UNLINK error unlinking file.
69 ERR_FILE_MISSING file missing.
70 ERR_CODE_GEN_NOT_EXECUTABLE code gen script not executable. you may need to run `chmod +x` on your code gen script.
71 ERR_CODE_GEN_FAILED code generation failed.
72 ERR_CONFIG_WRITE_FAILED error writing config file.
73 ERR_UNSUPPORTED_FILE_TYPE unsupported file type.
74 ERR_URL_TRUNK URL is a trunk branch. make sure your project is in "branches/MAJOR.MINOR".
75 ERR_URL_TAGS URL is a tags branch. make sure your project is in "branches/MAJOR.MINOR".
76 ERR_URL_NOT_A_VERSION_BRANCH URL is not a version branch. make sure your project is in "branches/MAJOR.MINOR".
77 ERR_NETBEANS_PROJECT_EXISTS NetBeans project already exists. if you want to re-create a project delete exiting 'nbproject' dir.

Links

Generated with bugslist.

TODO

Generated with bugslist.

Bugslist

bugslist v0.2.127 (r7322)

compiled 2020-03-04 10:49:53 +1100 (Wed, 04 Mar 2020) by jj5

path: /home/jj5/bin/ext/bugslist/bin/bugslist.php

Copyright (C) 2016-2020 John Elliot V
License GPLv3+: GNU GPL version 3+ <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

HIGH

  • TODO: svnman.php: after version bump copy in config file from previous version.
  • TODO: svnman.php: when generating inc/version.php put a comment above VERSION_PATCH with a link to the latest inc/version.php on the relevant version branch.

MEDIUM

  • TODO: test.sh: we need much more extensive testing here. Make sure all subcommands get used and in various ways.
  • TODO: test.sh: we need a failing test here...
  • TODO: test.sh: we need a failing test here...
  • TODO: test.sh: probably need this test to go into TestRunner_Manager.
  • TODO: test.sh: probably need more happy path tests...
  • TODO: Manager.php: put some error handling around this...
  • TODO: svnman.php: this spec should probably be moved into the Settings class and be used for input validation.
  • TODO: svnman.php: this program needs better reporting. The current "all or nothing" ouutput is no good and needs to be revised. Basically there should be no output on success and only a brief error message on failure. The current verbose output can be retained for if a --debug or --verbose option is added.
  • TODO: svnman.php: need to support other version file formats. Especially *.cfg and maybe *.ini formats. Note that *.cfg file format is a key value format that is compatible with Unix shell environment config.
  • TODO: svnman.php: add a --debug command-line option. Be less verbose if it's not specified.
  • TODO: svnman.php: add a 'latest-branch' subcommand that reports the current branch and the latest branch (and if they're the same or different).
  • TODO: svnman.php: add support for 'browse' subcommand.
  • TODO: svnman.php: clean up after ourselves, delete temp files and directories...
  • TODO: svnman.php: add support for --tarball generation during release.
  • TODO: svnman.php: add a --json argument which causes program output to be in stable JSON format for better software integration options. Enable JSON output for 'version', 'errors', and 'help' too.
  • TODO: svnman.php: in gen-vars subcommand support --prefix option for putting env var names in a namespace...
  • TODO: svnman.php: add --error ERROR_CODE|ERROR_NAME option to `svnman errors` which will print out detailled error information for the particular error indicated.
  • TODO: svnman.php: add a --bug BUG_NUMBER argument. The BUG_NUMBER to be included in commit messages.
  • TODO: svnman.php: when updating version file, don't just update a single file, but update all version files, allowing for there to be multiple version file formats used in a single project. This will entail verifying the all version files agree with each other as regards the version number.
  • TODO: svnman.php: grep for ERR_ constants and report if <= 1 (i.e. declared but unused).
  • TODO: svnman.php: svnman get-error-code --error-name ERROR_NAME
  • TODO: svnman.php: svnman get-error-name --error-code ERROR_CODE
  • TODO: svnman.php: svnman get-error-info --error ERROR_NAME|ERROR_CODE
  • TODO: svnman.php: if --phpbom is nominated during `svnman create` then write the version file to src/code/0-bootstrap/2-version.php and not to inc/version.php.
  • TODO: svnman.php: only output stack trace on error if --debug is specified or error hint === PLEASE_INFORM.
  • TODO: svnman.php: support single and double quotes on strings in *.cfg files
  • TODO: svnman.php: add support for a 'get' subcommand. Will get the latest version (or a specified version) of a project from Subversion and check it out into a local working copy (usually under the working base). If no project name is specified then list available projects.
  • TODO: svnman.php: svnman 'status' subcommand.
    • output the state of all svn:externals
    • report all DEV MAJOR.MINOR versions (branches/MAJOR.MINOR)
    • report all PROD MAJOR.MINOR versions (tags/latest/MAJOR.MINOR)
    • it would be nice to figure out if a project is a candidate for release
      • i.e. if it hasn't very recently been released
        • check PATCH number probably, or maybe Revision.
  • TODO: svnman.php: ensure all external projects have no changes before operating
  • TODO: svnman.php: for `svnman list` support formatting options:
    • --format console-list
    • --format console-table
    • --format wiki-list
    • --format wiki-table

LOW

  • THINK: Manager.php: do we want to just automatically mkdir -p the working base..?
  • THINK: svnman.php: do we want an optional argument --version-file for manually nominating the version file..? (At the moment we prefer convention over configuration.)
  • THINK: svnman.php: enable JSON output for tests?
  • THINK: svnman.php: consider adding an interactive mode that will confirm options or ask questions.
  • THINK: svnman.php: if we're gonna allow refactoring of error name constants we might want a compatibility thing that aliases old/deprecated names to new names. But such a facility isn't necessary yet.
  • THINK: svnman.php: think about what other files/directories we might want to create upon `svnman create` if --phpbom is specified.
  • THINK: svnman.php: hint for unauthorised --non-interactive `svn` operations which fail: "please authenticate"
  • THINK: svnman.php: operate without version file for legacy support? (to test delete the version file and run subcommands)
  • THINK: svnman.php: should we create a 'man page' for svnman..? That might be fun. I've never created a man page before!