Tuesday, 3 November 2015

In Progress : How to use Versionner in Pharo Smalltalk 4

What is Versionner For

Versionner is for helping to automate writing the ConfigurationOf<PackageName> for a package or project, i.e. it assists you in creating Metacello configurations.

A Metacello configuration is a managed code package, which explicitly defines the dependencies between one package (perhaps your own package that you are developing) and other packages.

n.b. Groups in Metacello/Versionner are unrelated to groups in Nautilus/the System Browser.

The "MyKillerApp" example

MyKillerGame is a project with several loadable Pharo code packages:
    - containing base classes with the domain model of your application
    - a package providing own UI widgets for your application
    - a package containing classes with the board of your killer game, ...
    - a test package with SUnit tests that test classes in the MyKillerGame-Core package
    - a test package with unit tests for MyKillerGame-UI-Widgets
    - a test package with unit tests for MyKillerGame-UI-Board

So with this structure:
 - the code is split into a domain model package and UI code package
 - the test are separated from the code packages, which makes it easier to deploy the completed KillerGame out to end-users, later on.  Having the tests in separate packages allows you to either load them for development or leave leave them unloaded in the production version
 - you have a test package for each implementation package

Working through the Example with Versionner

Open Versionner
  - in Pharo 4 .  left-click (i.e action-click) the Pharo desktop, World Menu | Tools | Versionner
  - in Pharo 5 .  ???

Versionner opens up a list of configurations in the image
   (is that the meta-repository list of configurations that the image knows of? i.e. the one which is shown in the Configuration Browser?
    is that the list of configurations which have already been loaded into the image?)

Two initial options:
"New project" - Create a new configuration for your project
"Load Project" - Load a configuration from a repository
and a third, greyed-out option
"Open project"  (which can also be achieved by double-clicking on a package listed in the browser pane

Create the new project
Create a new configuration project "MyKillerGame", using "New project"
New project opens up a "Name of the new project" dialogue box, followed by an "Author identification" dialog, creates a development version of the project, and then brings up the main Versionner window

It also
   automatically defines a class ConfigurationOfMyKillerGame.
      (This will hold all the Metacello load definitions),
   automatically creates a package "ConfigurationOfMyKillerGame".
      (This package is automatically placed in the "Configurations" group in the Packages pane of the Nautilus/System Browser).

Once the new project has been created, you can update the development version whenever you need to, using 'Save to Development'.

Define the package dependencies

Next,  you need to define the package dependencies in the main Versionner window - the Dependency Browser.

The dependency browser shows you the dependencies of the already-loaded packages. If you reference a class in another package from within your project, it will be displayed in dependency browser

- add the necessary package
- add loading dependencies
     the three packages of tests are each dependent on the package they test, because the test classes need the classes to test, so
        - "MyKillerGame-Tests-Core" is dependent on the classes in "MyKillerGame-Core"
        - MyKillerGame-Tests-UI-Widgets requires MyKillerGame-UI-Widgets
        - MyKillerGame-Tests-UI-Board has a dependency on MyKillerGame-UI-Board
        - MyKillerGame-UI-Board requires MyKillerGame-UI-Widgets
             (as the game board requires fancy widgets )
        - MyKillerGame-UI-Board requires MyKillerGame-Core
             (as the game board requires the game's domain model/non UI logic)

Once these are defined, each and every package has all dependencies on any package that needs to be
loaded before the package itself works.  And if every package within a project has all its dependencies defined, then the project as a whole has all its dependencies defined.

So we have one core package (with the game logic), two packages for UI related stuff,  and three packages related to testing.

We can then group them in Versionner by adding Metacello Groups:
   "Core" - containing the "MyKillerGame-Core" package
    "UI" -  containing the "MyKillerGame-UI-Board" and "MyKillerApp-UI-Widgets" packages
    "Tests" - containing "MyKillerGame-Tests-Core", MyKillerGame-Tests-UI-Widgets" and "MyKillerGame-Tests-UI-Board"

This means that later you can load the "Core" group specifically, and Metacello will load just the packages listed in this group.  Likewise, you could just load the "Tests" group. Metacello would then will load the packages in this group and the packages that they were defined as dependent on - their required packages.

There are two pseudo [Versionner?] groups
 "all" - you define this, so it will load all packages related so your project.
 "default" -> Monticello loads this group is by default
                             (i.e. if you do not give another group or package to load).

So in our example we can either
   put all packages into the "all" group
   put the group "Core","UI", "Tests" and tests into the [seems to be something missing here] group
        (This is the easier and more logical approach of the two)
            N.b. Groups can include packages and can also include other groups.

"all" should include all packages, as the name suggests.  It's up to you how you define the "default".

For the MyKillerGame, the two best approaches are either
  a) define "default" group to have  group "all" (so by default anything is loaded for development)
  b) define "default" group to have groups "Core" and "UI" (so by default anything is loaded for deployment, without tests)

Once the project repository is set up, you can directly commit the ConfigurationOf<PackageName> to the repository using "Commit the Project"?' There is no need to upload the changed  "ConfigurationOfXXX " package using the Monticello browser.  You can directly upload it into the repository from Versionner.

[Does this mean the package and project also do not need to be Monticello'd?  That committing only the ConfigurationOf<PackageName> automagically stores the project and the packes within the project to their repositories?]


Beyond here lies Work-in-progress


Open some of the configuration classes in the browser and try to understand them.

Pharo 4:   load from my ConfigurationBrowser
Pharo 5:   load from the new CatalogBrowser that Esteban wrote. I polished it a little bit but
                     also extended Spotter to be able to load configurations from Catalog.

Example: In a fresh Pharo 5 image hit SHIFT + Enter (to open Spotter) and enter "DesktopMan", dependening on
                     network latency  you quickly get "DesktopManager" project. If not wait a few seconds.
                     If you hit enter the project will be loaded. No need to open the Catalog Browser anymore. :simple_smile:


When the project is loaded just hit SHIFT+Enter again to open spotter and enter the class
name ConfigurationOfDesktopManager. Hit enter and Nautilus will open on the class
(the package is not selected by default but this is a known bug)

Check out the baseline defined in class ConfigurationOfDesktopManager.
Here we have two simple packages
    "DesktopManager-Core" (implementation)
    "DesktopManager-Tests-Core" with the tests.

There is a dependency in the spec defined from "DesktopManager-Tests-Core" requiring "DesktopManager-Core" as the test package need the implementation package with the code to test.

There is also a group "Core" and a group "Tests".
The pseudo group "default" is defined to load the groups "Core" and "Tests".

The Baseline "0.1-baseline" defined in #baseline01: just defines depencies (=from which the load order is calculated by Metacello) and the groups.

Beside the Baseline there is also a real initial version "0.1.0" defined in #version010: method using this baseline and defining the appropriate versions of each package that fit together.

Semantic Versionning (http://semver.org/) is recommended - then you'd version you project with 0.1.0, 0.2.0, 0.3.0 etc, as you define milestones.

Some users of "MyKillerGame" might not be interested in a specific version. They just want to have a stable thing to work with.

Others might want to use the latest development version, which might well be unstable

This is what developer-defined symbolic versions like #stable or #baseline are for.

#development (usually references the latest baseline. This way, the latest version of each package is loaded in the right order).

see also:

Versionner - Commit Tool for Pharo (2/2)
Dependency Managment for Pharo


GitHub  dalehenrich/metacello-work
metacello-work - Metacello is a package management system for Smalltalk


define dependencies to other projects (for instance if you use JSON you might want to define a dependency to NeoJSON)

If the config is done right it will load NeoJSON first and then your code

versionner also allows to mark a combination of packages as "Version x.y.z"



Once the development version is complete, you can 'Release version'.  Release versions are frozen - further changes to them are not allowed.

No comments:

Post a Comment