Packages, Monticello, Iceberg & Tonel

A package groups classes and extension methods (methods in protocols named *PackageName).

28.1 Packages

A package groups classes and extension methods (methods in protocols named *PackageName). It is the unit of versioning and loading. Naming convention: Project-Component (Bank-Core, Bank-Tests, Bank-UI), with tags inside a package for finer grouping. Query them with BankAccount package name (→ 'Bank-Core') or (PackageOrganizer default packageNamed: 'Bank-Core') classes.

28.2 Monticello (legacy and Squeak)

Versions are .mcz files (zip archives containing source and metadata), named Package-Author.N.mcz.

Repositories: local directories, HTTP servers (SqueakSource, SqueakMap, the now read-only SmalltalkHub archive), and GemStone/Squeak servers.

The Monticello Browser saves, loads, merges, and diffs package versions.

Still the standard in Squeak and Cuis-adjacent communities (Cuis uses .pck.st files and Git); Pharo keeps Monticello internally as the layer below Iceberg.

28.3 Iceberg: Git in Pharo

Since Pharo 7, Iceberg is the Git client:

Open *Sources → Iceberg* (or *Browse → Git Repositories browser*).

Add a repository: *Clone from github.com* (SSH or HTTPS), *Import from existing local repository*, or *New repository*.

Specify the code subdirectory (convention: src).

Create or select packages and add them to the repository.

Commit (writes Tonel files and commits), then Push.

Use branches, pull, merge (with a diff/merge tool for Smalltalk code), and view history.

SSH credentials are configured in *Settings → Tools → Git/Iceberg* (or Iceberg's credentials window). Under the hood Iceberg uses libgit2 through FFI.

28.4 Tonel: the file format

Tonel stores one file per class, readable and diff-friendly:

A Tonel class file (BankAccount.class.st):

The older FileTree format (one file per method) is still readable by Iceberg and Metacello but no longer recommended.

my-bank/
├── .project                       {'srcDirectory' : 'src'}
├── README.md
├── .smalltalk.ston                (CI configuration)
└── src/
    ├── .properties                {#format : #tonel}
    ├── BaselineOfBank/
    │   ├── BaselineOfBank.class.st
    │   └── package.st
    ├── Bank-Core/
    │   ├── BankAccount.class.st
    │   ├── InsufficientFunds.class.st
    │   ├── Number.extension.st     (extension methods)
    │   └── package.st
    └── Bank-Tests/
        ├── BankAccountTest.class.st
        └── package.st
"
I represent a bank account with an owner and a balance.
"
Class {
	#name : 'BankAccount',
	#superclass : 'Object',
	#instVars : [
		'owner',
		'balance'
	],
	#category : 'Bank-Core',
	#package : 'Bank-Core',
	#tag : 'Model'
}

{ #category : 'operations' }
BankAccount >> deposit: anAmount [

	anAmount <= 0 ifTrue: [ ^ self error: 'Deposit must be positive' ].
	balance := balance + anAmount
]

28.5 Continuous integration

smalltalkCI runs tests for Pharo, Squeak, and GemStone on GitHub Actions or other CI services. .smalltalk.ston:

On GitHub Actions, the hpi-swt/setup-smalltalkCI action installs smalltalkCI; a job then runs smalltalkci -s Pharo64-13 (use a matrix such as Pharo64-12, Pharo64-13 to test several versions).

SmalltalkCISpec {
  #loading : [
    SCIMetacelloLoadSpec {
      #baseline : 'Bank',
      #directory : 'src',
      #platforms : [ #pharo ]
    }
  ],
  #testing : { #coverage : { #packages : [ 'Bank-*' ] } }
}