├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .gitattributes ├── .github ├── bump-module-version.yml └── workflows │ ├── github-registry.yml │ ├── objectscript-quality.yml │ └── runtests.yml ├── .gitignore ├── .iris_init ├── .vscode ├── launch.json └── settings.json ├── Dockerfile ├── Dockerfile_mini ├── Dockerfile_vanilla ├── LICENSE ├── README.md ├── dev.md ├── docker-compose.yml ├── iris.script ├── module.xml ├── src └── dc │ └── sample │ ├── ObjectScript.cls │ └── PersistentClass.cls └── tests └── dc └── sample └── unittests ├── TestObjectScript.cls └── TestPersistentClass.cls /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.224.2/containers/docker-existing-docker-compose 3 | { 4 | "name": "objecscript-docker-template devcontainer", 5 | 6 | // Use the same recipe as creates the container we use when working locally. 7 | "dockerComposeFile": [ 8 | "../docker-compose.yml" 9 | ], 10 | 11 | "service": "iris", 12 | 13 | "workspaceFolder": "/home/irisowner/dev", 14 | 15 | "customizations": { 16 | "vscode": { 17 | // This provides the elements of the connection object which require different values when connecting to the workspace within the container, 18 | // versus those in .vscode/settings.json which apply when operating locally on the workspace files. 19 | // We define and use a `server` so that (a) a user-level `objectscript.conn.server` properly doesn't override us, and (b) so InterSystems 20 | // Server Manager can also be used. 21 | "settings": { 22 | "objectscript.conn" :{ 23 | "server": "devcontainer", 24 | "active": true 25 | }, 26 | "intersystems.servers": { 27 | "devcontainer": { 28 | "username": "SuperUser", 29 | "password": "SYS", 30 | "webServer": { 31 | "scheme": "http", 32 | "host": "127.0.0.1", 33 | "port": 52773 34 | } 35 | } 36 | }, 37 | "python.defaultInterpreterPath":"/usr/irissys/bin/irispython" 38 | }, 39 | // Add the IDs of extensions we want installed when the container is created. 40 | // Currently (March 2022) `intersystems.language-server` fails to run within the container (alpine platform). 41 | // Issue is probably https://github.com/intersystems/language-server/issues/185 and/or https://github.com/intersystems/language-server/issues/32 42 | // Crash gets reported to the user, after which `intersystems-community.vscode-objectscript` falls back to 43 | // using its TextMate grammar for code coloring. 44 | "extensions": [ 45 | "ms-python.python", 46 | "ms-python.vscode-pylance", 47 | "intersystems-community.vscode-objectscript", 48 | "intersystems.language-server", 49 | "intersystems-community.servermanager", 50 | "ms-vscode.docker" 51 | ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | .git 3 | .env -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cls linguist-language=ObjectScript 2 | *.mac linguist-language=ObjectScript 3 | *.int linguist-language=ObjectScript 4 | *.inc linguist-language=ObjectScript 5 | *.csp linguist-language=Html 6 | 7 | *.sh text eol=lf 8 | *.cls text eol=lf 9 | *.mac text eol=lf 10 | *.int text eol=lf 11 | *.inc text eol=lf 12 | Dockerfil* text eol=lf 13 | -------------------------------------------------------------------------------- /.github/bump-module-version.yml: -------------------------------------------------------------------------------- 1 | name: versionbump 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | pull_request: 9 | branches: 10 | - master 11 | - main 12 | release: 13 | types: 14 | - released 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Bump version 22 | run: | 23 | git config --global user.name 'ProjectBot' 24 | git config --global user.email 'bot@users.noreply.github.com' 25 | VERSION=$(sed -n '0,/.*\(.*\)<\/Version>.*/s//\1/p' module.xml) 26 | VERSION=`echo $VERSION | awk -F. '/[0-9]+\./{$NF++;print}' OFS=.` 27 | sed -i "0,/\(.*\)<\/Version>/s//$VERSION<\/Version>/" module.xml 28 | git add module.xml 29 | git commit -m 'auto bump version' 30 | git push 31 | -------------------------------------------------------------------------------- /.github/workflows/github-registry.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish a Docker image to ghcr.io 2 | on: 3 | 4 | # publish on pushes to the main branch (image tagged as "latest") 5 | # image name: will be: ghcr.io/${{ github.repository }}:latest 6 | # e.g.: ghcr.io/intersystems-community/intersystems-iris-dev-template:latest 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | docker_publish: 13 | runs-on: "ubuntu-20.04" 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | # https://github.com/marketplace/actions/push-to-ghcr 19 | - name: Build and publish a Docker image for ${{ github.repository }} 20 | uses: macbre/push-to-ghcr@master 21 | with: 22 | image_name: ${{ github.repository }} 23 | github_token: ${{ secrets.GITHUB_TOKEN }} 24 | # optionally push to the Docker Hub (docker.io) 25 | # docker_io_token: ${{ secrets.DOCKER_IO_ACCESS_TOKEN }} # see https://hub.docker.com/settings/security -------------------------------------------------------------------------------- /.github/workflows/objectscript-quality.yml: -------------------------------------------------------------------------------- 1 | name: objectscriptquality 2 | on: push 3 | 4 | jobs: 5 | linux: 6 | name: Linux build 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Execute ObjectScript Quality Analysis 11 | run: wget https://raw.githubusercontent.com/litesolutions/objectscriptquality-jenkins-integration/master/iris-community-hook.sh && sh ./iris-community-hook.sh 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/runtests.yml: -------------------------------------------------------------------------------- 1 | name: unittest 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | pull_request: 9 | branches: 10 | - master 11 | - main 12 | release: 13 | types: 14 | - released 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v2 21 | - name: Build and Test 22 | uses: docker/build-push-action@v2 23 | with: 24 | context: . 25 | push: false 26 | load: true 27 | tags: ${{ github.repository }}:${{ github.sha }} 28 | build-args: TESTS=1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | 4 | -------------------------------------------------------------------------------- /.iris_init: -------------------------------------------------------------------------------- 1 | :alias enablebi do EnableDeepSee^%SYS.cspServer("/csp/"_$zcvt($namespace,"L")) ; 2 | :alias ssl x "n $namespace set $namespace=""%SYS"", name=$S(""$1""="""":""DefaultSSL"",1:""$1"") do:'##class(Security.SSLConfigs).Exists(name) ##class(Security.SSLConfigs).Create(name)" ; 3 | :alias createdb do $SYSTEM.SQL.Execute("CREATE DATABASE $1") ; 4 | :alias installipm s r=##class(%Net.HttpRequest).%New(),r.Server="pm.community.intersystems.com",r.SSLConfiguration="ISC.FeatureTracker.SSL.Config" d r.Get("/packages/zpm/latest/installer"),$system.OBJ.LoadStream(r.HttpResponse.Data,"c") ; 5 | :alias add%all x "n $namespace set $namespace=""%SYS"",P(""Globals"")=""%DEFAULTDB"",sc=##class(Config.Namespaces).Create(""%All"",.P)" ; 6 | :alias exportglobal d $System.OBJ.Export("$1.GBL","$2$1.xml") ; 7 | :alias err d $System.Status.DisplayError($1) ; 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "objectscript", 6 | "request": "launch", 7 | "name": "ObjectScript Debug Class", 8 | "program": "##class(PackageSample.ObjectScript).Test()", 9 | }, 10 | { 11 | "type": "objectscript", 12 | "request": "attach", 13 | "name": "ObjectScript Attach", 14 | "processId": "${command:PickProcess}", 15 | "system": true 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | 4 | "Dockerfile*": "dockerfile", 5 | "iris.script": "objectscript" 6 | }, 7 | "objectscript.conn" :{ 8 | "ns": "USER", 9 | "username": "_SYSTEM", 10 | "password": "SYS", 11 | "docker-compose": { 12 | "service": "iris", 13 | "internalPort": 52773 14 | }, 15 | "active": true 16 | }, 17 | "sqltools.connections": [ 18 | { 19 | "namespace": "USER", 20 | "connectionMethod": "Server and Port", 21 | "showSystem": false, 22 | "previewLimit": 50, 23 | "server": "localhost", 24 | "port": 32770, 25 | "askForPassword": false, 26 | "driver": "InterSystems IRIS", 27 | "name": "objectscript-docker", 28 | "username": "_SYSTEM", 29 | "password": "SYS" 30 | } 31 | ] 32 | 33 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE=intersystemsdc/irishealth-community 2 | ARG IMAGE=intersystemsdc/iris-community 3 | FROM $IMAGE 4 | 5 | WORKDIR /home/irisowner/dev 6 | 7 | ARG TESTS=0 8 | ARG MODULE="objectscript-template" 9 | ARG NAMESPACE="USER" 10 | 11 | ## Embedded Python environment 12 | ENV IRISUSERNAME "_SYSTEM" 13 | ENV IRISPASSWORD "SYS" 14 | ENV IRISNAMESPACE "USER" 15 | ENV PYTHON_PATH=/usr/irissys/bin/ 16 | ENV PATH "/usr/irissys/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/irisowner/bin" 17 | 18 | COPY .iris_init /home/irisowner/.iris_init 19 | 20 | RUN --mount=type=bind,src=.,dst=. \ 21 | iris start IRIS && \ 22 | iris session IRIS < iris.script && \ 23 | ([ $TESTS -eq 0 ] || iris session iris -U $NAMESPACE "##class(%ZPM.PackageManager).Shell(\"test $MODULE -v -only\",1,1)") && \ 24 | iris stop IRIS quietly 25 | -------------------------------------------------------------------------------- /Dockerfile_mini: -------------------------------------------------------------------------------- 1 | # The most minimumalistic dockerfile possible. 2 | # No embedded python support, no unit-testing, no aliases. 3 | ARG IMAGE=intersystemsdc/irishealth-community 4 | ARG IMAGE=intersystemsdc/iris-community 5 | FROM $IMAGE 6 | 7 | WORKDIR /home/irisowner/dev 8 | 9 | RUN --mount=type=bind,src=.,dst=. \ 10 | iris start IRIS && \ 11 | iris session IRIS < iris.script && \ 12 | iris stop IRIS quietly 13 | -------------------------------------------------------------------------------- /Dockerfile_vanilla: -------------------------------------------------------------------------------- 1 | FROM containers.intersystems.com/intersystems/iris-community:latest-preview 2 | 3 | RUN --mount=type=bind,src=.,dst=/home/irisowner/irislab <write ##class(dc.sample.ObjectScript).Test() 35 | ``` 36 | ## How to start coding 37 | This repository is ready to code in VSCode with ObjectScript plugin. 38 | Install [VSCode](https://code.visualstudio.com/), [Docker](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) and [ObjectScript](https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript) plugin and open the folder in VSCode. 39 | Open /src/cls/PackageSample/ObjectScript.cls class and try to make changes - it will be compiled in running IRIS docker container. 40 | ![docker_compose](https://user-images.githubusercontent.com/2781759/76656929-0f2e5700-6547-11ea-9cc9-486a5641c51d.gif) 41 | 42 | Feel free to delete PackageSample folder and place your ObjectScript classes in a form 43 | /src/Package/Classname.cls 44 | [Read more about folder setup for InterSystems ObjectScript](https://community.intersystems.com/post/simplified-objectscript-source-folder-structure-package-manager) 45 | 46 | The script in Installer.cls will import everything you place under /src into IRIS. 47 | 48 | 49 | ## What's inside the repository 50 | 51 | ### Dockerfile 52 | 53 | The simplest Dockerfile which starts IRIS and imports code from /src folder into it. 54 | Use the related docker-compose.yml to easily setup additional parametes like port number and where you map keys and host folders. 55 | 56 | 57 | ### .vscode/settings.json 58 | 59 | Settings file to let you immediately code in VSCode with [VSCode ObjectScript plugin](https://marketplace.visualstudio.com/items?itemName=daimor.vscode-objectscript)) 60 | 61 | ### .vscode/launch.json 62 | Config file if you want to debug with VSCode ObjectScript 63 | 64 | [Read about all the files in this article](https://community.intersystems.com/post/dockerfile-and-friends-or-how-run-and-collaborate-objectscript-projects-intersystems-iris) 65 | -------------------------------------------------------------------------------- /dev.md: -------------------------------------------------------------------------------- 1 | # useful commands 2 | ## clean up docker 3 | use it when docker says "There is no space left on device". It will remove built but not used images and other temporary files. 4 | ``` 5 | docker system prune -f 6 | ``` 7 | 8 | ## if the previous doesn't help anymore: 9 | ``` 10 | docker system prune -a 11 | ``` 12 | 13 | ``` 14 | docker rm -f $(docker ps -qa) 15 | ``` 16 | 17 | ## build container with no cache 18 | ``` 19 | docker compose build --no-cache --progress=plain 20 | ``` 21 | ## start iris container 22 | ``` 23 | docker compose up -d 24 | ``` 25 | 26 | ## open iris terminal in docker 27 | ``` 28 | docker compose exec iris iris session iris -U USER 29 | ``` 30 | 31 | ## map iris key from Mac home directory to IRIS in container 32 | - ~/iris.key:/usr/irissys/mgr/iris.key 33 | 34 | ## install git in the docker image 35 | ## add git in dockerfile 36 | USER root 37 | RUN apt update && apt-get -y install git 38 | 39 | USER ${ISC_PACKAGE_MGRUSER} 40 | 41 | 42 | ## install docker-compose 43 | ``` 44 | sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 45 | 46 | sudo chmod +x /usr/local/bin/docker-compose 47 | 48 | ``` 49 | 50 | ## select zpm test registry 51 | ``` 52 | repo -n registry -r -url https://test.pm.community.intersystems.com/registry/ -user test -pass PassWord42 53 | ``` 54 | 55 | ## get back to public zpm registry 56 | ``` 57 | repo -r -n registry -url https://pm.community.intersystems.com/ 58 | ``` 59 | 60 | ## export a global in runtime into the repo 61 | ``` 62 | d $System.OBJ.Export("GlobalD.GBL","/home/irisowner/dev/src/gbl/GlobalD.xml") 63 | ``` 64 | 65 | ## create a web app in dockerfile 66 | ``` 67 | zn "%SYS" \ 68 | write "Create web application ...",! \ 69 | set webName = "/csp/irisweb" \ 70 | set webProperties("NameSpace") = "IRISAPP" \ 71 | set webProperties("Enabled") = 1 \ 72 | set webProperties("CSPZENEnabled") = 1 \ 73 | set webProperties("AutheEnabled") = 32 \ 74 | set webProperties("iKnowEnabled") = 1 \ 75 | set webProperties("DeepSeeEnabled") = 1 \ 76 | set sc = ##class(Security.Applications).Create(webName, .webProperties) \ 77 | write "Web application "_webName_" has been created!",! 78 | ``` 79 | 80 | 81 | 82 | ``` 83 | do $SYSTEM.OBJ.ImportDir("/home/irisowner/dev/src",, "ck") 84 | ``` 85 | 86 | 87 | ### run tests described in the module 88 | 89 | IRISAPP>zpm 90 | IRISAPP:zpm>load /home/irisowner/dev 91 | IRISAPP:zpm>test package-name 92 | 93 | ### install ZPM with one line 94 | // Install ZPM 95 | set $namespace="%SYS", name="DefaultSSL" do:'##class(Security.SSLConfigs).Exists(name) ##class(Security.SSLConfigs).Create(name) set url="https://pm.community.intersystems.com/packages/zpm/latest/installer" Do ##class(%Net.URLParser).Parse(url,.comp) set ht = ##class(%Net.HttpRequest).%New(), ht.Server = comp("host"), ht.Port = 443, ht.Https=1, ht.SSLConfiguration=name, st=ht.Get(comp("path")) quit:'st $System.Status.GetErrorText(st) set xml=##class(%File).TempFilename("xml"), tFile = ##class(%Stream.FileBinary).%New(), tFile.Filename = xml do tFile.CopyFromAndSave(ht.HttpResponse.Data) do ht.%Close(), $system.OBJ.Load(xml,"ck") do ##class(%File).Delete(xml) 96 | 97 | 98 | ## add git 99 | USER root 100 | 101 | RUN apt update && apt-get -y install git 102 | 103 | USER ${ISC_PACKAGE_MGRUSER} 104 | 105 | 106 | ## Python virtual environment 107 | python -m vevn .venv -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | iris: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | restart: always 8 | ports: 9 | - 1972 10 | - 52773 11 | - 53773 12 | volumes: 13 | - ./:/home/irisowner/dev 14 | -------------------------------------------------------------------------------- /iris.script: -------------------------------------------------------------------------------- 1 | ;do $System.OBJ.LoadDir("/home/irisowner/dev/src","ck",,1) 2 | 3 | ;disabling password expire for development purposes 4 | zn "%SYS" 5 | Do ##class(Security.Users).UnExpireUserPasswords("*") 6 | 7 | ; enabling callin for Embedded Python 8 | do ##class(Security.Services).Get("%Service_CallIn",.prop) 9 | set prop("Enabled")=1 10 | set prop("AutheEnabled")=48 11 | do ##class(Security.Services).Modify("%Service_CallIn",.prop) 12 | 13 | zpm "install passwordless" 14 | ; importing the source code of the repository as ZPM module 15 | zn "USER" 16 | zpm "load /home/irisowner/dev -v":1:1 17 | halt 18 | -------------------------------------------------------------------------------- /module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | objectscript-template 6 | 1.1.2 7 | module 8 | src 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/dc/sample/ObjectScript.cls: -------------------------------------------------------------------------------- 1 | Class dc.sample.ObjectScript 2 | { 3 | 4 | ClassMethod Test() As %Status 5 | { 6 | set a=42 7 | write "It works!",! 8 | return a 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/dc/sample/PersistentClass.cls: -------------------------------------------------------------------------------- 1 | Class dc.sample.PersistentClass Extends %Persistent 2 | { 3 | 4 | Property Test As %VarString; 5 | 6 | ClassMethod CreateRecord(ByRef id As %Integer) As %Status 7 | { 8 | set sc=$$$OK 9 | set objPC=..%New() 10 | set objPC.Test="Test string" 11 | set sc=objPC.%Save() 12 | set id=objPC.%Id() 13 | return sc 14 | } 15 | 16 | /// opens the record by id and reads its property 17 | ClassMethod ReadProperty(id As %Integer) As %Status 18 | { 19 | Set sc = $$$OK 20 | #dim obj as dc.sample.PersistentClass 21 | set obj=..%OpenId(id,,.sc) 22 | if $ISOBJECT(obj) write obj.Test 23 | Return sc 24 | } 25 | 26 | Storage Default 27 | { 28 | 29 | 30 | %%CLASSNAME 31 | 32 | 33 | Test 34 | 35 | 36 | ^dc.Package4C8F.PersistentC1A93D 37 | PersistentClassDefaultData 38 | ^dc.Package4C8F.PersistentC1A93D 39 | ^dc.Package4C8F.PersistentC1A93I 40 | ^dc.Package4C8F.PersistentC1A93S 41 | %Storage.Persistent 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/dc/sample/unittests/TestObjectScript.cls: -------------------------------------------------------------------------------- 1 | Class dc.sample.unittests.TestObjectScript Extends %UnitTest.TestCase 2 | { 3 | 4 | Method Test42() 5 | { 6 | Set tExpected=42 7 | set tResults= ##class(dc.sample.ObjectScript).Test() 8 | Do $$$AssertEquals(tResults,tExpected,tExpected_" = "_tResults) 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /tests/dc/sample/unittests/TestPersistentClass.cls: -------------------------------------------------------------------------------- 1 | Class dc.sample.unittests.TestCreateRecord Extends %UnitTest.TestCase 2 | { 3 | 4 | Method TestCreateRecord() 5 | { 6 | Set tExpected="Test string" 7 | set status=##class(dc.sample.PersistentClass).CreateRecord(.id) 8 | do $$$AssertStatusOK(status,"CreateRecord") 9 | set obj=##class(dc.sample.PersistentClass).%OpenId(id) 10 | if $IsObject(obj) { 11 | set tResults=obj.Test} 12 | else {set tResults="There is no such record with id="_id} 13 | Do $$$AssertEquals(tResults,tExpected,tExpected_" = "_tResults) 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------