├── .eslintrc.yml ├── .eslintrc.json ├── .github └── workflows │ └── ci.yml ├── action.yml ├── package.json ├── LICENSE ├── .gitignore ├── README.md └── index.js /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | commonjs: true 3 | es2021: true 4 | node: true 5 | plugins: 6 | - no-floating-promise 7 | extends: 'eslint:recommended' 8 | parserOptions: 9 | ecmaVersion: 12 10 | rules: 11 | require-await: error 12 | no-floating-promise/no-floating-promise: error 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 2018 14 | }, 15 | "rules": { 16 | } 17 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | npm: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | - run: npm ci 10 | - run: npm test 11 | 12 | self-test: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | smalltalk: [ Squeak64-trunk, Squeak32-4.5 ] 17 | os: [ macos-latest, windows-latest, ubuntu-latest ] 18 | steps: 19 | - uses: actions/checkout@v3 20 | - uses: hpi-swa/setup-smalltalkCI@v1 21 | with: 22 | smalltalk-image: ${{ matrix.smalltalk }} 23 | - if: runner.os != 'Windows' 24 | run: | 25 | smalltalkci --help 26 | [[ ! -z "${SMALLTALK_CI_HOME}" ]] || ( echo "SMALLTALK_CI_HOME not set" && false ) 27 | - shell: bash 28 | if: runner.os == 'Windows' 29 | run: smalltalkci --help -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup smalltalkCI' 2 | description: 'Set up smalltalkCI for testing Squeak/Smalltalk, Pharo, GemStone, 3 | and Moose projects' 4 | author: 'Software Architecture Group, Hasso Plattner Institute' 5 | inputs: 6 | smalltalk-image: 7 | description: 'Smalltalk image selection (see smalltalkCI''s list of 8 | supported images)' 9 | smalltalk-version: 10 | description: 'Deprecated, please use smalltalk-image' 11 | smalltalkCI-source: 12 | description: 'GitHub slug of the smalltalkCI source repository' 13 | required: false 14 | default: 'hpi-swa/smalltalkCI' 15 | smalltalkCI-branch: 16 | description: 'Branch or tag to use from smalltalkCI repository' 17 | required: false 18 | default: 'master' 19 | outputs: 20 | smalltalk-image: 21 | description: 'Smalltalk image selection' 22 | smalltalk-version: 23 | description: 'Deprecated, please use smalltalk-image' 24 | runs: 25 | using: 'node20' 26 | main: 'dist/index.js' 27 | branding: 28 | icon: 'box' 29 | color: 'blue' 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setup-smalltalkCI", 3 | "version": "1.1.1", 4 | "description": "This GitHub Action sets up smalltalkCI for testing Smalltalk projects.", 5 | "main": "index.js", 6 | "scripts": { 7 | "package": "ncc build index.js -o dist", 8 | "test": "eslint index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/hpi-swa/setup-smalltalkCI.git" 13 | }, 14 | "keywords": [ 15 | "smalltalkCI", 16 | "GitHub", 17 | "Actions", 18 | "Smalltalk" 19 | ], 20 | "engines": { 21 | "node": ">=20" 22 | }, 23 | "author": "Software Architecture Group, Hasso Plattner Institute", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/hpi-swa/setup-smalltalkCI/issues" 27 | }, 28 | "homepage": "https://github.com/hpi-swa/setup-smalltalkCI", 29 | "dependencies": { 30 | "@actions/core": "^1.10.1", 31 | "@actions/exec": "^1.1.1", 32 | "@actions/tool-cache": "^2.0.1" 33 | }, 34 | "devDependencies": { 35 | "@vercel/ncc": "^0.38.1", 36 | "eslint": "^8.56.0", 37 | "eslint-plugin-no-floating-promise": "^1.0.2", 38 | "jest": "^29.7.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Software Architecture Group, Hasso Plattner Institute 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | # Editors 4 | .vscode 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Other Dependency directories 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | # next.js build output 65 | .next 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # setup-smalltalkCI 2 | 3 | This GitHub Action sets up [smalltalkCI] for testing Smalltalk projects. 4 | 5 | ## Usage 6 | 7 | ### Basic 8 | 9 | ```yaml 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: hpi-swa/setup-smalltalkCI@v1 13 | id: smalltalkci 14 | with: 15 | smalltalk-image: 'Squeak64-trunk' 16 | - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} 17 | shell: bash 18 | timeout-minutes: 15 19 | ``` 20 | 21 | ### Testing Different Smalltalk Images 22 | 23 | ```yaml 24 | jobs: 25 | build: 26 | strategy: 27 | matrix: 28 | smalltalk: [ Squeak64-trunk, Pharo64-stable ] 29 | name: ${{ matrix.smalltalk }} 30 | steps: 31 | - uses: actions/checkout@v2 32 | - uses: hpi-swa/setup-smalltalkCI@v1 33 | with: 34 | smalltalk-image: ${{ matrix.smalltalk }} 35 | - run: smalltalkci -s ${{ matrix.smalltalk }} 36 | shell: bash 37 | timeout-minutes: 15 38 | ``` 39 | 40 | ### Testing Different Smalltalk Images with Different Configurations 41 | ```yaml 42 | jobs: 43 | build: 44 | strategy: 45 | matrix: 46 | smalltalk: [ Squeak64-trunk, Pharo64-stable ] 47 | smalltalk_config: [ .smalltalkA.ston, .smalltalkB.ston ] 48 | name: ${{ matrix.smalltalk }} 49 | steps: 50 | - uses: actions/checkout@v2 51 | - uses: hpi-swa/setup-smalltalkCI@v1 52 | with: 53 | smalltalk-image: ${{ matrix.smalltalk }} 54 | - run: smalltalkci -s ${{ matrix.smalltalk }} ${{ matrix.smalltalk_config }} 55 | shell: bash 56 | timeout-minutes: 15 57 | ``` 58 | 59 | ### Use a different branch or fork 60 | 61 | ```yaml 62 | steps: 63 | - uses: actions/checkout@v2 64 | - uses: hpi-swa/setup-smalltalkCI@v1 65 | id: smalltalkci 66 | with: 67 | smalltalk-image: 'Squeak64-trunk' 68 | smalltalkCI-branch: 'testing-branch' 69 | smalltalkCI-source: 'myfork/smalltalkCI' 70 | - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} 71 | shell: bash 72 | timeout-minutes: 15 73 | ``` 74 | 75 | 76 | ### Pharos-specific: Registering Repository in Iceberg 77 | 78 | Registering a repository in Iceberg allows developers to access the directory of the repository regardless of where it is located in the file system. 79 | This eases access to non-Smalltalk resources. 80 | To register the repository in Iceberg, you need to add `#registerInIceberg : true` to your `.smalltalk.ston` file. 81 | 82 | ```smalltalk 83 | (IceRepository registeredRepositoryIncludingPackage: self class package) location pathString 84 | ``` 85 | 86 | However, Iceberg requires the full commit history. 87 | `actions/checkout` provides by default only the latest one. 88 | Therefore we need to use an option to get all commits. 89 | (Only available for Pharo 7 and later version at this time). 90 | 91 | ```yaml 92 | steps: 93 | - uses: actions/checkout@v3 94 | with: 95 | fetch-depth: 0 # Option fetching all commits 96 | - uses: hpi-swa/setup-smalltalkCI@v1 97 | id: smalltalkci 98 | with: 99 | smalltalk-image: 'Squeak64-trunk' 100 | - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} 101 | shell: bash 102 | timeout-minutes: 15 103 | ``` 104 | 105 | 106 | [smalltalkCI]: https://github.com/hpi-swa/smalltalkCI 107 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process') 2 | const fs = require('fs') 3 | const os = require('os') 4 | const path = require('path') 5 | 6 | const core = require('@actions/core') 7 | const exec = require('@actions/exec') 8 | const io = require('@actions/io') 9 | const tc = require('@actions/tool-cache') 10 | 11 | const IS_LINUX = process.platform === 'linux' 12 | const IS_WINDOWS = process.platform === 'win32' 13 | 14 | const INSTALLATION_DIRECTORY = path.join(os.homedir(), '.smalltalkCI') 15 | const DEFAULT_BRANCH = 'master' 16 | const DEFAULT_SOURCE = 'hpi-swa/smalltalkCI' 17 | const LSB_FILE = '/etc/lsb-release' 18 | const UBUNTU_VERSION = getUbuntuVersion() 19 | const DEFAULT_64BIT_DEPS = 'libpulse0' 20 | const DEFAULT_32BIT_DEPS = `libc6-i386 libuuid1:i386${UBUNTU_VERSION == 18 ? ' libssl1.0.0:i386' : (UBUNTU_VERSION == 20 ? ' libssl1.1:i386': '')}` 21 | const PHARO_32BIT_DEPS = `${DEFAULT_32BIT_DEPS} libcairo2:i386` 22 | 23 | 24 | async function run() { 25 | try { 26 | let image 27 | const version = core.getInput('smalltalk-version') 28 | if (version.length > 0) { 29 | image = version 30 | core.warning('Please use "smalltalk-image". "smalltalk-version" is deprecated and will be removed in the future.') 31 | } else { 32 | image = core.getInput('smalltalk-image', { required: true }) 33 | } 34 | 35 | const is64bit = /^[a-zA-Z]*64-/.test(image) 36 | const isSqueak = isPlatform(image, 'squeak') 37 | const isEtoys = isPlatform(image, 'etoys') 38 | const isPharo = isPlatform(image, 'pharo') 39 | const isMoose = isPlatform(image, 'moose') 40 | const isGToolkit = isPlatform(image, 'gtoolkit') 41 | const isGemstone = isPlatform(image, 'gemstone') 42 | 43 | if (!isSqueak && !isEtoys && !isPharo && !isMoose && !isGToolkit && !isGemstone) { 44 | return core.setFailed(`Unsupported Smalltalk version "${image}".`) 45 | } 46 | 47 | core.setOutput('smalltalk-image', image) 48 | core.setOutput('smalltalk-version', version) 49 | 50 | const smalltalkCIBranch = core.getInput('smalltalkCI-branch') || DEFAULT_BRANCH 51 | const smalltalkCISource = core.getInput('smalltalkCI-source') || DEFAULT_SOURCE 52 | 53 | /* Download and extract smalltalkCI. */ 54 | console.log('Downloading and extracting smalltalkCI...') 55 | let tempDir = path.join(os.homedir(), '.smalltalkCI-temp') 56 | if (IS_WINDOWS) { 57 | const toolPath = await tc.downloadTool(`https://github.com/${smalltalkCISource}/archive/${smalltalkCIBranch}.zip`) 58 | tempDir = await tc.extractZip(toolPath, tempDir) 59 | } else { 60 | const toolPath = await tc.downloadTool(`https://github.com/${smalltalkCISource}/archive/${smalltalkCIBranch}.tar.gz`) 61 | tempDir = await tc.extractTar(toolPath, tempDir) 62 | } 63 | await io.mv(path.join(tempDir, `smalltalkCI-${smalltalkCIBranch}`), INSTALLATION_DIRECTORY) 64 | 65 | /* Install dependencies if any. */ 66 | if (IS_LINUX) { 67 | if (is64bit) { 68 | if (isSqueak || isEtoys) { 69 | await install64bitDependencies(DEFAULT_64BIT_DEPS) 70 | } 71 | } else { 72 | if (isSqueak || isEtoys) { 73 | await install32bitDependencies(DEFAULT_32BIT_DEPS) 74 | } else if (isPharo || isMoose || isGToolkit) { 75 | await install32bitDependencies(PHARO_32BIT_DEPS) 76 | } else if (isGemstone) { 77 | // nothing to, smalltalkCI will set up the system using GsDevKit_home 78 | } 79 | } 80 | } 81 | 82 | /* Set up smalltalkci command. */ 83 | core.addPath(path.join(INSTALLATION_DIRECTORY, 'bin')) 84 | 85 | if (!IS_WINDOWS) { 86 | /* Find and export smalltalkCI's env vars. */ 87 | const envList = child_process.execSync('smalltalkci --print-env').toString() 88 | for (const envItem of envList.split('\n')) { 89 | const parts = envItem.split('=') 90 | if (parts.length == 2) { 91 | core.exportVariable(parts[0], parts[1]) 92 | } 93 | } 94 | } 95 | } catch (error) { 96 | core.setFailed(error.message) 97 | } 98 | } 99 | 100 | async function install64bitDependencies(deps) { 101 | await exec.exec('sudo apt-get update') 102 | await exec.exec(`sudo apt-get install -qq --no-install-recommends ${deps}`) 103 | } 104 | 105 | async function install32bitDependencies(deps) { 106 | await exec.exec('sudo dpkg --add-architecture i386') 107 | await exec.exec('sudo apt-get update') 108 | await exec.exec(`sudo apt-get install -qq --no-install-recommends ${deps}`) 109 | } 110 | 111 | function getUbuntuVersion() { 112 | if (IS_LINUX && fs.existsSync(LSB_FILE)) { 113 | const contents = fs.readFileSync(LSB_FILE).toString(); 114 | if (contents.includes('DISTRIB_RELEASE=22')) { 115 | return 22 116 | } else if (contents.includes('DISTRIB_RELEASE=20')) { 117 | return 20 118 | } else if (contents.includes('DISTRIB_RELEASE=18')) { 119 | return 18 120 | } else { 121 | return -1 122 | } 123 | } else { 124 | return -1 125 | } 126 | } 127 | 128 | function isPlatform(image, name) { 129 | return image.toLowerCase().startsWith(name) 130 | } 131 | 132 | // eslint-disable-next-line no-floating-promise/no-floating-promise 133 | run() // return a Promise as specified by the GitHub Actions protocol 134 | --------------------------------------------------------------------------------