Testing and releasing Pharo with GitHub actions

Introduction

Hi 👋, Travis is becoming a pay to use service. So why not move to GitHub actions to test your Pharo project?

Here I'm presenting everything you need to know to test your project with GitHub Actions.

We'll also see how to release your project (also continuously ✨).

Testing with Smalltalk CI

The simplest case

To test a Pharo project, we will create a GitHub action. Upon each commit on the main branch, this action will test your project.

To do so, it:

  1. checks out your project
  2. runs Smalltalk CI on your project

To create the GitHub action, you need first to create a file under the folder <git root>/.github/workflows. Since the action is to test the project, I decided to name it test.yml, but any other name will work. So in my git repository I have a file in: <git root>/.github/workflows/test.yml

In the file write:

1name: CI 2 3env: 4 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 5 6# Controls when the action will run. Triggers the workflow on push or pull request 7# events but only for the development branch 8on: 9 push: 10 branches: 11 - main 12 13jobs: 14 build: 15 runs-on: ubuntu-latest 16 steps: 17 - uses: actions/checkout@v2 18 - uses: hpi-swa/setup-smalltalkCI@v1 19 id: smalltalkci 20 with: 21 smalltalk-version: Pharo64-8.0 22 - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} 23 shell: bash 24 timeout-minutes: 15 25

The first lines indicate when the action is triggered. In this simple case, it is triggered on each push on the branch main.

Then, the jobs part describes the steps of the CI. It runs on a Ubuntu image. There are three steps, (1) it checks out the last version of the project for the current branch, (2) it prepares the smalltalkCI tool, and (3) it runs smalltalkCI on your project for the Pharo64-8.0 image.

A more complex case

Indeed, you might want to test your project over several pharo versions. In this section, we see another example using GitHub actions matrix:

1jobs: 2 build: 3 runs-on: ubuntu-latest 4 strategy: 5 matrix: 6 smalltalk: [ Pharo64-8.0, Pharo64-9.0 ] 7 name: ${{ matrix.smalltalk }} 8 steps: 9 - uses: actions/checkout@v2 10 - uses: hpi-swa/setup-smalltalkCI@v1 11 with: 12 smalltalk-version: ${{ matrix.smalltalk }} 13 - run: smalltalkci -s ${{ matrix.smalltalk }} 14 shell: bash 15 timeout-minutes: 15 16

The name and the trigger part are the same as before. In the build part, we add a matrix strategy. In this strategy, we set the name of the Pharo versions compatible with our project. Then, in the steps, we tell SmallTalk CI to use the current smalltalk name of the matrix.

Testing Upon a Pull Request

It is also possible to test on each Pull Request instead of commit to the main branch. To do so, change the trigger part by

1on: 2 pull_request: 3 types: [assigned, opened, synchronize, reopened]

Many other trigger options exist; you should check them on the GitHub action page.

A final version of the file can be found here.

Releasing

Using GitHub action to test your project is nice, but we can do more. We will automatically release our project using GitHub Actions. To so, we create two other actions: one for common release, one for continuous release.

Release

To create a release action, we first create a new file, for example <git root>/.github/workflows/release.yml. This action is triggered upon release creation and will test the project and release an image with the project loaded.

1name: Release 2 3on: 4 release: 5 types: [created] 6 7jobs: 8 build: 9 runs-on: ubuntu-latest 10 env: 11 PROJECT_NAME: ${{ matrix.smalltalk }}-Moose 12 strategy: 13 matrix: 14 smalltalk: [ Pharo64-9.0, Pharo64-8.0 ] 15 name: ${{ matrix.smalltalk }} 16 steps: 17 - uses: actions/checkout@v2 18 - uses: hpi-swa/setup-smalltalkCI@v1 19 with: 20 smalltalk-version: ${{ matrix.smalltalk }} 21 - run: smalltalkci -s ${{ matrix.smalltalk }} 22 shell: bash 23 timeout-minutes: 15 24 25 - name: Package 26 run: | 27 mv /home/runner/.smalltalkCI/_builds/* . 28 mv TravisCI.image $PROJECT_NAME.image 29 mv TravisCI.changes $PROJECT_NAME.changes 30 zip -r $PROJECT_NAME.zip $PROJECT_NAME.image $PROJECT_NAME.changes *.sources pharo.version 31 ls 32 33 - name: Get release 34 id: get_release 35 uses: bruceadams/get-release@v1.2.2 36 env: 37 GITHUB_TOKEN: ${{ github.token }} 38 39 - name: Upload Release Asset 40 id: upload-release-asset 41 uses: actions/upload-release-asset@v1 42 env: 43 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 with: 45 upload_url: ${{ steps.get_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 46 asset_path: ./${{ env.PROJECT_NAME }}.zip 47 asset_name: ${{ env.PROJECT_NAME }}.zip 48 asset_content_type: application/zip

The above example is the one used by the Moose Project. First, we define an environment variable named <current matrix name>-Moose. In addition to the testing steps, we add three steps: Package takes the source file after testing the project (i.e. .image, .changes, .sources, and pharo.version) and zips them into one zip file with the current matrix name. Get release allows us to access the release GitHub API. Thus, we can access the upload URL of the release. Then, Upload Release Asset uploads the zip file created in the package step.

When developers release their code, the action downloads an image for each specified Pharo version, tests it, packages it, and uploads it in the GitHub release. Then, users can directly download the released version of the project, with project code loaded in the image.

Continuous release

For the continuous release, we add a schedule to trigger the GitHub actions. Thus, if the Pharo image evolves, our build will evolve with it.

Note that we have also changed the way to update the release. Indeed, the Update Release automatically creates a release and uploads the last version of the zip file.

1# This is a basic workflow to help you get started with Actions 2 3name: Continuous 4 5# Controls when the action will run. Triggers the workflow on push or pull request 6# events but only for the development branch 7on: 8 push: 9 branches: 10 - development 11 schedule: 12 # * is a special character in YAML so you have to quote this string 13 - cron: '0 0 * * *' 14 15jobs: 16 build: 17 runs-on: ubuntu-latest 18 env: 19 PROJECT_NAME: ${{ matrix.smalltalk }}-Moose 20 strategy: 21 matrix: 22 smalltalk: [ Pharo64-9.0, Pharo64-8.0 ] 23 name: ${{ matrix.smalltalk }} 24 steps: 25 - uses: actions/checkout@v2 26 - uses: hpi-swa/setup-smalltalkCI@v1 27 with: 28 smalltalk-version: ${{ matrix.smalltalk }} 29 - run: smalltalkci -s ${{ matrix.smalltalk }} 30 shell: bash 31 timeout-minutes: 15 32 33 - name: package 34 run: | 35 mv /home/runner/.smalltalkCI/_builds/* . 36 mv TravisCI.image $PROJECT_NAME.image 37 mv TravisCI.changes $PROJECT_NAME.changes 38 zip -r $PROJECT_NAME.zip $PROJECT_NAME.image $PROJECT_NAME.changes *.sources pharo.version 39 ls 40 41 - name: Update Release 42 uses: johnwbyrd/update-release@v1.0.0 43 with: 44 release: 'continuous' 45 token: ${{ secrets.GITHUB_TOKEN }} 46 files: ${{ env.PROJECT_NAME }}.zip

Add releases to Pharo Launcher

Finally, I want to share with you a little script to add the GitHub Release into the Pharo Launcher. To do so:

  1. Open the Pharo Launcher
  2. Open a Playground (Ctrl + O, Ctrl + W)
  3. Execute the following piece of code
1| sources | 2sources := { 3 PhLTemplateSource new 4 type: #HttpListing; 5 name: 'Moose'; 6 url: 'https://github.com/moosetechnology/Moose/releases'; 7 filterPattern: 'href="([^"]*/Pharo[0-9][^"]*.zip)"'; 8 templateNameFormat: '{6} ({5})' }. 9PhLUserTemplateSources sourcesFile writeStreamDo: [ :s | 10 (STON writer on: s) 11 newLine: String lf; 12 prettyPrint: true; 13 nextPut: sources ]

This piece of code creates a local source file for the Pharo Launcher template. In the source file, it specifies using an HttpListing from the release page of GitHub. Then, with a filter pattern, it creates a beautiful list inside the Pharo Launcher.

To adapt the piece of code for your project, you need to change the name: and url: method parameters.

Pharo Launcher with linkg to GitHub actions

Resources

The three files: test, release, and continuous can be found in the Moose project repository

Thanks

I'd like to thanks the authors of smalltalkCI for their incredible work!

Thanks C. Fuhrman for the typos fixes. 🍌