From 83bc9208e71afebdb902fba156fe58214d3003fd Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 6 Oct 2021 17:11:44 +0100 Subject: [PATCH 01/27] First Rough Draft --- docs/tutorials/add-runtime.md | 165 ++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 docs/tutorials/add-runtime.md diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md new file mode 100644 index 000000000..76c42b037 --- /dev/null +++ b/docs/tutorials/add-runtime.md @@ -0,0 +1,165 @@ +# Creating a new functions runtime + +This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). + +## Getting started +Function Runtimes allow you to execute code written for languages as apart of the Appwrite Stack as serverless functions. +Appwrite's Goal is to support as many function runtimes as possible. + +## 1. Prerequisites +In order for a function runtime to work a few prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: + + - [ ] The Language in question must be able to run a web server that can serve json and text. + - [ ] The Language must support being built or having its dependencies installed via a CI + - [ ] The Runtime must be able to be packaged into a docker container + - [ ] Both Compiled and Interpreted languages work with appwrite's execution model but both are written in slightly different ways. + +It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. +> If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). + +### 1.1 Fork the Appwrite repository + +Before making any changes, you will need to fork Appwrite's repository to keep branches on the official repo clean. To do that, visit [Appwrite's Runtime repository](https://github.com/appwrite/php-runtimes) and click on the fork button. + +[![Fork button](https://github.com/appwrite/appwrite/raw/master/docs/tutorials/images/fork.png)](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/images/fork.png) + +This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using `git clone` command: +```bash +$ git clone COPIED_URL +``` + +> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a really clean and simple visual Git client. + +Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `master` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. + +## 2. Implement new runtime + +### 2.1 Preparing the files for your new runtime +The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance if I was to write a Rust Runtime with the version 1.55 the folder name would be: `rust-1.55` + +Within that folder you will need to create a few basic files that all Appwrite runtimes require: +``` +Dockerfile - Dockerfile that explains how the container will be built. +README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 one. +``` + +### 2.2 Differences between compiled and interpreted runtimes +Runtimes within Appwrite are created differently depending on if they are compiled or interpreted this is due to the fundamental differences between the two ways of running the code. + +Interpreted languages have both a `build.sh` file and a `launch.sh` file. +The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. +The build script is always executed during the build stage of tag deployment. + +The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies this tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. + +--- +Compiled Languages only have a `build.sh` file. +The `build.sh` will for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled Runtimes **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. + +#### Note: +`/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need. + +### 2.3 Writing the runtime +Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes. + +The best way to go about writing a runtime is like so: +1. Write a web server which runs on port 3000 and uses any IP Address (0.0.0.0) +3. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message +4. Decode the executors JSON POST request. This normally looks like so: +```json +{ + "path": "/usr/code", // Disregard for Compiled Languages + "file": "index.js", // Disregard for Compiled Languages + "env": { + "hello":"world!" + }, + "payload":"An Example Payload", + "timeout": 10 +} +``` +For a compiled language you can disregard the `path` and `file` attribute if you like, + +`timeout` is also an optional parameter to deal with, if you can handle it please do otherwise it doesn't matter since the connection will be dropped by the executor. + +You must create two classes for users. A `Request` Class and a `Response` class +The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function +The `Response` class must have two functions. +- An `send(string)` function which will return text to the request +- and a `json(object)` function which will return JSON to the request setting the appropriate headers + +For a interpreted language use the `path` and `file` parameters to find the file and require it. +Please make sure to add appropriate checks to make sure the imported type is actually a function that you can execute + +5. Execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. + +### 2.4 The Error Schema +All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user. +```json +{ + "code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed. + "message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user. +} +``` + +### 2.5 Writing your Dockerfile +The Dockerfile is very important as it's the environment you are creating to run build the runtime and also run the code if you are writing an Interpreted Runtime (Compiled runtimes will use an alpine or ubuntu image) + +The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are a runtime for. + +Next in your Dockerfile at the top add the docker image you want to base it off at the top like so: +``` +FROM Dart:2.12 +``` +This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for. + +Next copy your source code and set the work directory for the image like so: +``` +WORKDIR /usr/local/src +COPY . /usr/local/src +``` + +Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh` you can run commands in Dockerfile's using the `RUN` prefix like so: +``` +RUN chmod +x ./build.sh +RUN chmod +x ./launch.sh +``` +Note: Do not chmod a `launch.sh` file if you don't have one. + +If needed use the `RUN` commands to install any dependencies you require for a build stage. + +Finally you'll add a `CMD` command. For a interpreted language this should be: +``` +CMD ["/usr/local/src/launch.sh"] +``` +Since this will use your launch script when the runtime starts. + +For a compiled language this must be: +``` +CMD ["tail", "-f", "/dev/null"] +``` +so the build steps can be run. + +## 3. Adding the runtime to the runtimes list +In `src/Runtimes/Runtimes` create a new entry in the `__construct()` method in the Runtimes class like so: +``` +$dart = new Runtime('dart', 'Dart'); +$dart->addVersion('2.12', 'dart-runtime:2.12', 'appwrite-ubuntu:20.04', [System::X86, System::ARM]); +$this->runtimes['dart'] = $dart; +``` +This is an example of what you would do for a compiled language such as dart. + +The first line is creating a new language entry, The first parameter is the internal name and the second one is the external one which is what the user will see in Appwrite. + +The second line adds a new version to the language entry, I'll break down the parameters: +``` +1: Version - The version of the runtime you are creating. +2: Build Image - The image used to build the code +3: Run Image - The image used to run the code. +For interpreted languages this is normally the same as the Build Image, but for compiled languages this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" +We recommend using Alpine when possible and using ubuntu if the runtime doesn't work on alpine. +4: Platforms Supported - These are the architectures this runtime is available to. +``` +The third line simply adds the new runtime to the main list. + +## 4. Adding tests + From d9f04e31e29c08429331b984b9696830515a33c4 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 6 Oct 2021 23:45:44 +0100 Subject: [PATCH 02/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 64 +++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 76c42b037..f8c111f42 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -3,16 +3,15 @@ This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). ## Getting started -Function Runtimes allow you to execute code written for languages as apart of the Appwrite Stack as serverless functions. -Appwrite's Goal is to support as many function runtimes as possible. +Function Runtimes allow you to execute code written for any language as apart of the Appwrite Stack as serverless functions! Appwrite's Goal is to support as many function runtimes as possible. ## 1. Prerequisites -In order for a function runtime to work a few prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: +In order for a function runtime to work two prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: - [ ] The Language in question must be able to run a web server that can serve json and text. - - [ ] The Language must support being built or having its dependencies installed via a CI - [ ] The Runtime must be able to be packaged into a docker container - - [ ] Both Compiled and Interpreted languages work with appwrite's execution model but both are written in slightly different ways. + + Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. > If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). @@ -44,17 +43,17 @@ README.md - A readme file explaining the runtime and any special notes for the r ``` ### 2.2 Differences between compiled and interpreted runtimes -Runtimes within Appwrite are created differently depending on if they are compiled or interpreted this is due to the fundamental differences between the two ways of running the code. +Runtimes within Appwrite are created differently depending on if they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. Interpreted languages have both a `build.sh` file and a `launch.sh` file. The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. The build script is always executed during the build stage of tag deployment. -The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies this tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. +The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. --- Compiled Languages only have a `build.sh` file. -The `build.sh` will for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled Runtimes **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. +The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. #### Note: `/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need. @@ -63,9 +62,9 @@ The `build.sh` will for a compiled runtime is used to move the user's source cod Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes. The best way to go about writing a runtime is like so: -1. Write a web server which runs on port 3000 and uses any IP Address (0.0.0.0) -3. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message -4. Decode the executors JSON POST request. This normally looks like so: +Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following: +1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message. +2. Decode the executor's JSON POST request. This normally looks like so: ```json { "path": "/usr/code", // Disregard for Compiled Languages @@ -79,18 +78,19 @@ The best way to go about writing a runtime is like so: ``` For a compiled language you can disregard the `path` and `file` attribute if you like, -`timeout` is also an optional parameter to deal with, if you can handle it please do otherwise it doesn't matter since the connection will be dropped by the executor. +`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise it doesn't matter since the connection will simply be dropped by the executor. -You must create two classes for users. A `Request` Class and a `Response` class -The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function +You must create two classes for users to use within their scripts. A `Request` Class and a `Response` class +The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function. +Request always goes before response in the user's function parameters. The `Response` class must have two functions. -- An `send(string)` function which will return text to the request +- A `send(string)` function which will return text to the request - and a `json(object)` function which will return JSON to the request setting the appropriate headers For a interpreted language use the `path` and `file` parameters to find the file and require it. -Please make sure to add appropriate checks to make sure the imported type is actually a function that you can execute +Please make sure to add appropriate checks to make sure the imported file is actually a function that you can execute. -5. Execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. +5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. ### 2.4 The Error Schema All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user. @@ -104,11 +104,11 @@ All errors that occur during the execution of a user's function **MUST** be retu ### 2.5 Writing your Dockerfile The Dockerfile is very important as it's the environment you are creating to run build the runtime and also run the code if you are writing an Interpreted Runtime (Compiled runtimes will use an alpine or ubuntu image) -The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are a runtime for. +The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are creating a runtime for. -Next in your Dockerfile at the top add the docker image you want to base it off at the top like so: -``` -FROM Dart:2.12 +Next in your Dockerfile at the start add the docker image you want to base it off at the top like so: +```bash +FROM Dart:2.12 # Dart used as an example. ``` This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for. @@ -118,14 +118,14 @@ WORKDIR /usr/local/src COPY . /usr/local/src ``` -Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh` you can run commands in Dockerfile's using the `RUN` prefix like so: +Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so: ``` RUN chmod +x ./build.sh RUN chmod +x ./launch.sh ``` Note: Do not chmod a `launch.sh` file if you don't have one. -If needed use the `RUN` commands to install any dependencies you require for a build stage. +If needed use the `RUN` commands to install any dependencies you require for the build stage. Finally you'll add a `CMD` command. For a interpreted language this should be: ``` @@ -139,7 +139,21 @@ CMD ["tail", "-f", "/dev/null"] ``` so the build steps can be run. -## 3. Adding the runtime to the runtimes list +## 3. Building your docker image and adding it to the list +With your runtime successfully created you can now move on to building your docker image and adding it to the script files used for generating all of the image files. + +Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to it. The following is an example with dart version 2.12 +``` +echo 'Dart 2.12...' +docker build -t dart-runtime:2.12 ./runtimes/dart-2.12 +``` +Next open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross platform compiles and deploying it to docker hub. The following is an example also with dart version 2.12: +``` +echo 'Dart 2.12...' +docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push +``` + +## 4. Adding the runtime to the runtimes list In `src/Runtimes/Runtimes` create a new entry in the `__construct()` method in the Runtimes class like so: ``` $dart = new Runtime('dart', 'Dart'); @@ -161,5 +175,5 @@ We recommend using Alpine when possible and using ubuntu if the runtime doesn't ``` The third line simply adds the new runtime to the main list. -## 4. Adding tests +## 5. Adding tests From 0554d26754360652166da8a908b6c9a36f852e15 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 7 Oct 2021 10:10:00 +0100 Subject: [PATCH 03/27] Add tests section and Raising a PR Section --- docs/tutorials/add-runtime.md | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index f8c111f42..ec0802106 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -177,3 +177,60 @@ The third line simply adds the new runtime to the main list. ## 5. Adding tests +### 5.1 Writing your test execution script +Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for, as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema: +```json +{ + "normal": "Hello World!", + "env1": request.env['ENV1'], // ENV1 from the request environment variable + "payload": request.payload, // Payload from the request +} +``` +### 5.2 Creating the test packaging script for your runtime +With your test execution written you can move on to writing the script used to package your test execution script into a tarball for later use by the test system. Move into `/test/resources` again and notice how we have shell scripts for all runtimes we have made tests for. + +Go ahead and create a shell script yourself with your language name. As an example the shell script name for dart would be `package-dart.sh` + +Within this newly created script copy paste this script and replace all the `LANGUAGE_NAME` parts with your language's name +``` +echo 'LANGUAGE_NAME Packaging...' +rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz +tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME . +``` +go ahead and save this folder then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: +``` +chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh +``` +The first section changes the permissions of your script so you can execute it, while the second part actually executes the script and packages up your function. + +NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. + +### 5.3 Adding your runtime to the main testing script +Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests` as of the time of writing this tutorial this is on line 27. + +Once you have find this go ahead and add your own entry into this array like so: +```php +'LANGUAGE_NAME-VERSION' => [ + 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', + 'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME + 'timeout' => 15, + 'runtime' => 'LANGUAGE_NAME-VERSION', + 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. + 'filename' => 'Test file' // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME +], +``` +Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version. + +Once you have done this and saved it, it is finally time to move onto one of the final steps. + +### 5.4 Running the tests. +Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a docker container with the test script and start running going through all the runtimes making sure to test them thoroughly. + +If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure your ready to respond to any feedback which can arise during our code review. + +## 6. Raise a pull request +First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted. + +## ![face_with_head_bandage](https://github.githubassets.com/images/icons/emoji/unicode/1f915.png) Stuck ? + +If you need any help with the contribution, feel free to head over to [our discord channel](https://appwrite.io/discord) and we'll be happy to help you out. From 54f8c7792847734af5528201837de41c7cfe4c71 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 7 Oct 2021 10:10:51 +0100 Subject: [PATCH 04/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 238 +++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index ec0802106..05e196af7 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -1,4 +1,240 @@ -# Creating a new functions runtime +# Creating a new functions runtime 🏃 + +This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). + +## Getting started +Function Runtimes allow you to execute code written for any language as apart of the Appwrite Stack as serverless functions! Appwrite's Goal is to support as many function runtimes as possible. + +## 1. Prerequisites +In order for a function runtime to work two prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: + + - [ ] The Language in question must be able to run a web server that can serve json and text. + - [ ] The Runtime must be able to be packaged into a docker container + + Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. + +It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. +> If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). + +### 1.1 Fork the Appwrite repository + +Before making any changes, you will need to fork Appwrite's repository to keep branches on the official repo clean. To do that, visit [Appwrite's Runtime repository](https://github.com/appwrite/php-runtimes) and click on the fork button. + +[![Fork button](https://github.com/appwrite/appwrite/raw/master/docs/tutorials/images/fork.png)](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/images/fork.png) + +This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using `git clone` command: +```bash +$ git clone COPIED_URL +``` + +> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a really clean and simple visual Git client. + +Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `master` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. + +## 2. Implement new runtime + +### 2.1 Preparing the files for your new runtime +The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance if I was to write a Rust Runtime with the version 1.55 the folder name would be: `rust-1.55` + +Within that folder you will need to create a few basic files that all Appwrite runtimes require: +``` +Dockerfile - Dockerfile that explains how the container will be built. +README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 one. +``` + +### 2.2 Differences between compiled and interpreted runtimes +Runtimes within Appwrite are created differently depending on if they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. + +Interpreted languages have both a `build.sh` file and a `launch.sh` file. +The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. +The build script is always executed during the build stage of tag deployment. + +The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. + +--- +Compiled Languages only have a `build.sh` file. +The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. + +#### Note: +`/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need. + +### 2.3 Writing the runtime +Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes. + +The best way to go about writing a runtime is like so: +Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following: +1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message. +2. Decode the executor's JSON POST request. This normally looks like so: +```json +{ + "path": "/usr/code", // Disregard for Compiled Languages + "file": "index.js", // Disregard for Compiled Languages + "env": { + "hello":"world!" + }, + "payload":"An Example Payload", + "timeout": 10 +} +``` +For a compiled language you can disregard the `path` and `file` attribute if you like, + +`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise it doesn't matter since the connection will simply be dropped by the executor. + +You must create two classes for users to use within their scripts. A `Request` Class and a `Response` class +The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function. +Request always goes before response in the user's function parameters. +The `Response` class must have two functions. +- A `send(string)` function which will return text to the request +- and a `json(object)` function which will return JSON to the request setting the appropriate headers + +For a interpreted language use the `path` and `file` parameters to find the file and require it. +Please make sure to add appropriate checks to make sure the imported file is actually a function that you can execute. + +5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. + +### 2.4 The Error Schema +All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user. +```json +{ + "code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed. + "message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user. +} +``` + +### 2.5 Writing your Dockerfile +The Dockerfile is very important as it's the environment you are creating to run build the runtime and also run the code if you are writing an Interpreted Runtime (Compiled runtimes will use an alpine or ubuntu image) + +The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are creating a runtime for. + +Next in your Dockerfile at the start add the docker image you want to base it off at the top like so: +```bash +FROM Dart:2.12 # Dart used as an example. +``` +This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for. + +Next copy your source code and set the work directory for the image like so: +``` +WORKDIR /usr/local/src +COPY . /usr/local/src +``` + +Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so: +``` +RUN chmod +x ./build.sh +RUN chmod +x ./launch.sh +``` +Note: Do not chmod a `launch.sh` file if you don't have one. + +If needed use the `RUN` commands to install any dependencies you require for the build stage. + +Finally you'll add a `CMD` command. For a interpreted language this should be: +``` +CMD ["/usr/local/src/launch.sh"] +``` +Since this will use your launch script when the runtime starts. + +For a compiled language this must be: +``` +CMD ["tail", "-f", "/dev/null"] +``` +so the build steps can be run. + +## 3. Building your docker image and adding it to the list +With your runtime successfully created you can now move on to building your docker image and adding it to the script files used for generating all of the image files. + +Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to it. The following is an example with dart version 2.12 +``` +echo 'Dart 2.12...' +docker build -t dart-runtime:2.12 ./runtimes/dart-2.12 +``` +Next open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross platform compiles and deploying it to docker hub. The following is an example also with dart version 2.12: +``` +echo 'Dart 2.12...' +docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push +``` + +## 4. Adding the runtime to the runtimes list +In `src/Runtimes/Runtimes` create a new entry in the `__construct()` method in the Runtimes class like so: +``` +$dart = new Runtime('dart', 'Dart'); +$dart->addVersion('2.12', 'dart-runtime:2.12', 'appwrite-ubuntu:20.04', [System::X86, System::ARM]); +$this->runtimes['dart'] = $dart; +``` +This is an example of what you would do for a compiled language such as dart. + +The first line is creating a new language entry, The first parameter is the internal name and the second one is the external one which is what the user will see in Appwrite. + +The second line adds a new version to the language entry, I'll break down the parameters: +``` +1: Version - The version of the runtime you are creating. +2: Build Image - The image used to build the code +3: Run Image - The image used to run the code. +For interpreted languages this is normally the same as the Build Image, but for compiled languages this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" +We recommend using Alpine when possible and using ubuntu if the runtime doesn't work on alpine. +4: Platforms Supported - These are the architectures this runtime is available to. +``` +The third line simply adds the new runtime to the main list. + +## 5. Adding tests + +### 5.1 Writing your test execution script +Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for, as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema: +```json +{ + "normal": "Hello World!", + "env1": request.env['ENV1'], // ENV1 from the request environment variable + "payload": request.payload, // Payload from the request +} +``` +### 5.2 Creating the test packaging script for your runtime +With your test execution written you can move on to writing the script used to package your test execution script into a tarball for later use by the test system. Move into `/test/resources` again and notice how we have shell scripts for all runtimes we have made tests for. + +Go ahead and create a shell script yourself with your language name. As an example the shell script name for dart would be `package-dart.sh` + +Within this newly created script copy paste this script and replace all the `LANGUAGE_NAME` parts with your language's name +``` +echo 'LANGUAGE_NAME Packaging...' +rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz +tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME . +``` +go ahead and save this folder then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: +``` +chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh +``` +The first section changes the permissions of your script so you can execute it, while the second part actually executes the script and packages up your function. + +NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. + +### 5.3 Adding your runtime to the main testing script +Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests` as of the time of writing this tutorial this is on line 27. + +Once you have find this go ahead and add your own entry into this array like so: +```php +'LANGUAGE_NAME-VERSION' => [ + 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', + 'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME + 'timeout' => 15, + 'runtime' => 'LANGUAGE_NAME-VERSION', + 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. + 'filename' => 'Test file' // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME +], +``` +Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version. + +Once you have done this and saved it, it is finally time to move onto one of the final steps. + +### 5.4 Running the tests. +Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a docker container with the test script and start running going through all the runtimes making sure to test them thoroughly. + +If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure your ready to respond to any feedback which can arise during our code review. + +## 6. Raise a pull request +First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted. + +## ![face_with_head_bandage](https://github.githubassets.com/images/icons/emoji/unicode/1f915.png) Stuck ? + +If you need any help with the contribution, feel free to head over to [our discord channel](https://appwrite.io/discord) and we'll be happy to help you out. +# Creating a new functions runtime 🏃 This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). From 8c7a7e438b4aebf99c644ac2cd7cc60a8c261e4d Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 7 Oct 2021 10:25:53 +0100 Subject: [PATCH 05/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 237 ---------------------------------- 1 file changed, 237 deletions(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 05e196af7..7cd30ac03 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -216,243 +216,6 @@ Once you have find this go ahead and add your own entry into this array like so: 'timeout' => 15, 'runtime' => 'LANGUAGE_NAME-VERSION', 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. - 'filename' => 'Test file' // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME -], -``` -Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version. - -Once you have done this and saved it, it is finally time to move onto one of the final steps. - -### 5.4 Running the tests. -Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a docker container with the test script and start running going through all the runtimes making sure to test them thoroughly. - -If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure your ready to respond to any feedback which can arise during our code review. - -## 6. Raise a pull request -First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted. - -## ![face_with_head_bandage](https://github.githubassets.com/images/icons/emoji/unicode/1f915.png) Stuck ? - -If you need any help with the contribution, feel free to head over to [our discord channel](https://appwrite.io/discord) and we'll be happy to help you out. -# Creating a new functions runtime 🏃 - -This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). - -## Getting started -Function Runtimes allow you to execute code written for any language as apart of the Appwrite Stack as serverless functions! Appwrite's Goal is to support as many function runtimes as possible. - -## 1. Prerequisites -In order for a function runtime to work two prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: - - - [ ] The Language in question must be able to run a web server that can serve json and text. - - [ ] The Runtime must be able to be packaged into a docker container - - Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. - -It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. -> If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). - -### 1.1 Fork the Appwrite repository - -Before making any changes, you will need to fork Appwrite's repository to keep branches on the official repo clean. To do that, visit [Appwrite's Runtime repository](https://github.com/appwrite/php-runtimes) and click on the fork button. - -[![Fork button](https://github.com/appwrite/appwrite/raw/master/docs/tutorials/images/fork.png)](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/images/fork.png) - -This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using `git clone` command: -```bash -$ git clone COPIED_URL -``` - -> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a really clean and simple visual Git client. - -Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `master` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. - -## 2. Implement new runtime - -### 2.1 Preparing the files for your new runtime -The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance if I was to write a Rust Runtime with the version 1.55 the folder name would be: `rust-1.55` - -Within that folder you will need to create a few basic files that all Appwrite runtimes require: -``` -Dockerfile - Dockerfile that explains how the container will be built. -README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 one. -``` - -### 2.2 Differences between compiled and interpreted runtimes -Runtimes within Appwrite are created differently depending on if they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. - -Interpreted languages have both a `build.sh` file and a `launch.sh` file. -The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. -The build script is always executed during the build stage of tag deployment. - -The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. - ---- -Compiled Languages only have a `build.sh` file. -The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. - -#### Note: -`/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need. - -### 2.3 Writing the runtime -Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes. - -The best way to go about writing a runtime is like so: -Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following: -1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message. -2. Decode the executor's JSON POST request. This normally looks like so: -```json -{ - "path": "/usr/code", // Disregard for Compiled Languages - "file": "index.js", // Disregard for Compiled Languages - "env": { - "hello":"world!" - }, - "payload":"An Example Payload", - "timeout": 10 -} -``` -For a compiled language you can disregard the `path` and `file` attribute if you like, - -`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise it doesn't matter since the connection will simply be dropped by the executor. - -You must create two classes for users to use within their scripts. A `Request` Class and a `Response` class -The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function. -Request always goes before response in the user's function parameters. -The `Response` class must have two functions. -- A `send(string)` function which will return text to the request -- and a `json(object)` function which will return JSON to the request setting the appropriate headers - -For a interpreted language use the `path` and `file` parameters to find the file and require it. -Please make sure to add appropriate checks to make sure the imported file is actually a function that you can execute. - -5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. - -### 2.4 The Error Schema -All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user. -```json -{ - "code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed. - "message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user. -} -``` - -### 2.5 Writing your Dockerfile -The Dockerfile is very important as it's the environment you are creating to run build the runtime and also run the code if you are writing an Interpreted Runtime (Compiled runtimes will use an alpine or ubuntu image) - -The first thing you need to do is find a docker image to base your runtime off, You can find these at [Docker Hub](https://hub.docker.com). If possible try to use verified official builds of the language you are creating a runtime for. - -Next in your Dockerfile at the start add the docker image you want to base it off at the top like so: -```bash -FROM Dart:2.12 # Dart used as an example. -``` -This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for. - -Next copy your source code and set the work directory for the image like so: -``` -WORKDIR /usr/local/src -COPY . /usr/local/src -``` - -Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so: -``` -RUN chmod +x ./build.sh -RUN chmod +x ./launch.sh -``` -Note: Do not chmod a `launch.sh` file if you don't have one. - -If needed use the `RUN` commands to install any dependencies you require for the build stage. - -Finally you'll add a `CMD` command. For a interpreted language this should be: -``` -CMD ["/usr/local/src/launch.sh"] -``` -Since this will use your launch script when the runtime starts. - -For a compiled language this must be: -``` -CMD ["tail", "-f", "/dev/null"] -``` -so the build steps can be run. - -## 3. Building your docker image and adding it to the list -With your runtime successfully created you can now move on to building your docker image and adding it to the script files used for generating all of the image files. - -Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to it. The following is an example with dart version 2.12 -``` -echo 'Dart 2.12...' -docker build -t dart-runtime:2.12 ./runtimes/dart-2.12 -``` -Next open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross platform compiles and deploying it to docker hub. The following is an example also with dart version 2.12: -``` -echo 'Dart 2.12...' -docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push -``` - -## 4. Adding the runtime to the runtimes list -In `src/Runtimes/Runtimes` create a new entry in the `__construct()` method in the Runtimes class like so: -``` -$dart = new Runtime('dart', 'Dart'); -$dart->addVersion('2.12', 'dart-runtime:2.12', 'appwrite-ubuntu:20.04', [System::X86, System::ARM]); -$this->runtimes['dart'] = $dart; -``` -This is an example of what you would do for a compiled language such as dart. - -The first line is creating a new language entry, The first parameter is the internal name and the second one is the external one which is what the user will see in Appwrite. - -The second line adds a new version to the language entry, I'll break down the parameters: -``` -1: Version - The version of the runtime you are creating. -2: Build Image - The image used to build the code -3: Run Image - The image used to run the code. -For interpreted languages this is normally the same as the Build Image, but for compiled languages this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" -We recommend using Alpine when possible and using ubuntu if the runtime doesn't work on alpine. -4: Platforms Supported - These are the architectures this runtime is available to. -``` -The third line simply adds the new runtime to the main list. - -## 5. Adding tests - -### 5.1 Writing your test execution script -Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for, as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema: -```json -{ - "normal": "Hello World!", - "env1": request.env['ENV1'], // ENV1 from the request environment variable - "payload": request.payload, // Payload from the request -} -``` -### 5.2 Creating the test packaging script for your runtime -With your test execution written you can move on to writing the script used to package your test execution script into a tarball for later use by the test system. Move into `/test/resources` again and notice how we have shell scripts for all runtimes we have made tests for. - -Go ahead and create a shell script yourself with your language name. As an example the shell script name for dart would be `package-dart.sh` - -Within this newly created script copy paste this script and replace all the `LANGUAGE_NAME` parts with your language's name -``` -echo 'LANGUAGE_NAME Packaging...' -rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME . -``` -go ahead and save this folder then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: -``` -chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh -``` -The first section changes the permissions of your script so you can execute it, while the second part actually executes the script and packages up your function. - -NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. - -### 5.3 Adding your runtime to the main testing script -Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests` as of the time of writing this tutorial this is on line 27. - -Once you have find this go ahead and add your own entry into this array like so: -```php -'LANGUAGE_NAME-VERSION' => [ - 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', - 'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME - 'timeout' => 15, - 'runtime' => 'LANGUAGE_NAME-VERSION', - 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. - 'filename' => 'Test file' // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME ], ``` Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version. From 772bb346d2fea3143c6b2ecd1067f7cde49f113d Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:11:39 +0100 Subject: [PATCH 06/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 7cd30ac03..d446c18d5 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -67,8 +67,8 @@ Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0 2. Decode the executor's JSON POST request. This normally looks like so: ```json { - "path": "/usr/code", // Disregard for Compiled Languages - "file": "index.js", // Disregard for Compiled Languages + "path": "/usr/code", + "file": "index.js", "env": { "hello":"world!" }, @@ -76,7 +76,7 @@ Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0 "timeout": 10 } ``` -For a compiled language you can disregard the `path` and `file` attribute if you like, +For a compiled language you can disregard the `path` and `file` attribute if you like, `timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise it doesn't matter since the connection will simply be dropped by the executor. From 88c73cfa2259dfed3eb5f8a7de8b2a9b51c87ed3 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:12:08 +0100 Subject: [PATCH 07/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index d446c18d5..39c9b4d98 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -3,7 +3,7 @@ This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). ## Getting started -Function Runtimes allow you to execute code written for any language as apart of the Appwrite Stack as serverless functions! Appwrite's Goal is to support as many function runtimes as possible. +Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's serverless functions! Appwrite's goal is to support as many function runtimes as possible. ## 1. Prerequisites In order for a function runtime to work two prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: From 62440077cc00b7a4877da11e888afb937f128c26 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:12:24 +0100 Subject: [PATCH 08/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 39c9b4d98..994ee5b17 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -6,7 +6,7 @@ This document is part of the Appwrite contributors' guide. Before you continue r Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's serverless functions! Appwrite's goal is to support as many function runtimes as possible. ## 1. Prerequisites -In order for a function runtime to work two prerequisites **must** be met due to the way that Appwrite's Runtime Execution Model works. Theses are as followed: +In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works. Theses are as follows: - [ ] The Language in question must be able to run a web server that can serve json and text. - [ ] The Runtime must be able to be packaged into a docker container From a9a95b7c4bd6f3b4ae4c8658972ce33cf5ce96f8 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:12:32 +0100 Subject: [PATCH 09/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 994ee5b17..b466c0306 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -39,7 +39,7 @@ The first step to writing a new runtime is to create a folder within `/runtimes` Within that folder you will need to create a few basic files that all Appwrite runtimes require: ``` Dockerfile - Dockerfile that explains how the container will be built. -README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 one. +README.md - A readme file explaining the runtime and any special notes for the runtime. A good example of this is the PHP 8.0 runtime. ``` ### 2.2 Differences between compiled and interpreted runtimes From f24a381a0ace309bc27592f40ce26c3a87e46c4e Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:12:41 +0100 Subject: [PATCH 10/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index b466c0306..abc760293 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -43,7 +43,7 @@ README.md - A readme file explaining the runtime and any special notes for the r ``` ### 2.2 Differences between compiled and interpreted runtimes -Runtimes within Appwrite are created differently depending on if they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. +Runtimes within Appwrite are created differently depending on whether they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. Interpreted languages have both a `build.sh` file and a `launch.sh` file. The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. From b00ec1687201dc24b3b50dd623a2886fed59b38e Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:06 +0100 Subject: [PATCH 11/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index abc760293..5cef949a7 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -46,7 +46,7 @@ README.md - A readme file explaining the runtime and any special notes for the r Runtimes within Appwrite are created differently depending on whether they are compiled or interpreted. This is due to the fundamental differences between the two ways of running the code. Interpreted languages have both a `build.sh` file and a `launch.sh` file. -The `build.sh` file for a interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code then to copy it to the `/usr/code` folder which is packaged up and can be used later for running the server. +The `build.sh` file for an interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code and then to copy it to the `/usr/code` folder which is then packaged and can be used later for running the server. The build script is always executed during the build stage of tag deployment. The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. From 792159de9a1a53e3142560f954d313a8f28cd0d0 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:23 +0100 Subject: [PATCH 12/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 5cef949a7..104af1808 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -197,7 +197,7 @@ echo 'LANGUAGE_NAME Packaging...' rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME . ``` -go ahead and save this folder then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: +Go ahead and save this file. Then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: ``` chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh ``` From fff4321cf8769fad9f3a585ae018c24e18ca5ed9 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:31 +0100 Subject: [PATCH 13/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 104af1808..8c65e36c3 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -206,7 +206,7 @@ The first section changes the permissions of your script so you can execute it, NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. ### 5.3 Adding your runtime to the main testing script -Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests` as of the time of writing this tutorial this is on line 27. +Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. As of the time of writing this tutorial this is on `line 27`. Once you have find this go ahead and add your own entry into this array like so: ```php From 9795e823762e8fcb5fc3f61e4cf9536c2812a055 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:35 +0100 Subject: [PATCH 14/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 8c65e36c3..8cf71ec13 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -208,7 +208,7 @@ NOTE: If you ever want to repackage your script you can simply run: `./tests/res ### 5.3 Adding your runtime to the main testing script Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. As of the time of writing this tutorial this is on `line 27`. -Once you have find this go ahead and add your own entry into this array like so: +Once you have found this, go ahead and add your own entry into this array like so: ```php 'LANGUAGE_NAME-VERSION' => [ 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', From 03605bd097f132df633b75847d95eee94e29c315 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:46 +0100 Subject: [PATCH 15/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 8cf71ec13..972f414e8 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -223,7 +223,7 @@ Make sure to replace all instances of `LANGUAGE_NAME` with your language's name Once you have done this and saved it, it is finally time to move onto one of the final steps. ### 5.4 Running the tests. -Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a docker container with the test script and start running going through all the runtimes making sure to test them thoroughly. +Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a Docker container with the test script and start running through all the runtimes making sure to test them thoroughly. If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure your ready to respond to any feedback which can arise during our code review. From ab2c2686dfe492beb2661f1ce8828e7777b8a962 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 09:13:56 +0100 Subject: [PATCH 16/27] Update docs/tutorials/add-runtime.md Co-authored-by: Christy Jacob --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 972f414e8..3a95f2be2 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -225,7 +225,7 @@ Once you have done this and saved it, it is finally time to move onto one of the ### 5.4 Running the tests. Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a Docker container with the test script and start running through all the runtimes making sure to test them thoroughly. -If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure your ready to respond to any feedback which can arise during our code review. +If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure you're ready to respond to any feedback which can arise during our code review. ## 6. Raise a pull request First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted. From 932167204cb7b618b03832e7c928ce22767485ca Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 8 Oct 2021 11:57:19 +0100 Subject: [PATCH 17/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 3a95f2be2..c00ac701f 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -29,7 +29,7 @@ $ git clone COPIED_URL > To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a really clean and simple visual Git client. -Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `master` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. +Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `refactor` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. ## 2. Implement new runtime @@ -225,7 +225,7 @@ Once you have done this and saved it, it is finally time to move onto one of the ### 5.4 Running the tests. Running the tests is easy, simply run `docker-compose up` in the root of the `php-runtimes` folder. This will launch a Docker container with the test script and start running through all the runtimes making sure to test them thoroughly. -If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo, make sure you're ready to respond to any feedback which can arise during our code review. +If all tests pass then congratulations! You can now go ahead and file a PR against the `php-runtimes` repo making sure to target the `refactor` branch, make sure you're ready to respond to any feedback which can arise during our code review. ## 6. Raise a pull request First of all, commit the changes with the message `Added XXX Runtime` and push it. This will publish a new branch to your forked version of Appwrite. If you visit it at `github.com/YOUR_USERNAME/php-runtimes`, you will see a new alert saying you are ready to submit a pull request. Follow the steps GitHub provides, and at the end, you will have your pull request submitted. From cab3d205e214bb0c29bc42edb053dcb84e605ad4 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:42:21 +0100 Subject: [PATCH 18/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index c00ac701f..80f1842ec 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -206,7 +206,7 @@ The first section changes the permissions of your script so you can execute it, NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. ### 5.3 Adding your runtime to the main testing script -Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. As of the time of writing this tutorial this is on `line 27`. +Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. Once you have found this, go ahead and add your own entry into this array like so: ```php From 041f2186b7c1b6793b98c6d248cdf2c80fcb7ff8 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:42:37 +0100 Subject: [PATCH 19/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 80f1842ec..80d69c15a 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -201,7 +201,7 @@ Go ahead and save this file. Then `cd` into the root of the `php-runtimes` proje ``` chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh ``` -The first section changes the permissions of your script so you can execute it, while the second part actually executes the script and packages up your function. +This command adds execution permissions to your script and executes it. NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. From 07d6aca81134c6f9594b20366395d04f84ef9d50 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:42:45 +0100 Subject: [PATCH 20/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 80d69c15a..90202f02a 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -170,7 +170,7 @@ The second line adds a new version to the language entry, I'll break down the pa 2: Build Image - The image used to build the code 3: Run Image - The image used to run the code. For interpreted languages this is normally the same as the Build Image, but for compiled languages this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" -We recommend using Alpine when possible and using ubuntu if the runtime doesn't work on alpine. +We recommend using Alpine when possible and using Ubuntu if the runtime doesn't work on Alpine. 4: Platforms Supported - These are the architectures this runtime is available to. ``` The third line simply adds the new runtime to the main list. From 472e05ec5e345d1e89abb82b6500477bd45c854c Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:43:16 +0100 Subject: [PATCH 21/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 90202f02a..b072dd98a 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -9,7 +9,7 @@ Function Runtimes allow you to execute code written in any language and form the In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works. Theses are as follows: - [ ] The Language in question must be able to run a web server that can serve json and text. - - [ ] The Runtime must be able to be packaged into a docker container + - [ ] The Runtime must be able to be packaged into a Docker container Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. From 4e49c2f734a556f1fa93f4dad6ea34d84e331b67 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:43:20 +0100 Subject: [PATCH 22/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index b072dd98a..146260cb2 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -8,7 +8,7 @@ Function Runtimes allow you to execute code written in any language and form the ## 1. Prerequisites In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works. Theses are as follows: - - [ ] The Language in question must be able to run a web server that can serve json and text. + - [ ] The Language in question must be able to run a web server that can serve JSON and text. - [ ] The Runtime must be able to be packaged into a Docker container Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. From 9d7d0b7f2196cd8d8e6cb0ecfe50bc6970953d4d Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:43:33 +0100 Subject: [PATCH 23/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 146260cb2..eddb1d9c0 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -11,7 +11,7 @@ In order for a function runtime to work, two prerequisites **must** be met due t - [ ] The Language in question must be able to run a web server that can serve JSON and text. - [ ] The Runtime must be able to be packaged into a Docker container - Note: Both Compiled and Interpreted languages work with Appwrite's execution model but both are written in slightly different ways. + Note: Both Compiled and Interpreted languages work with Appwrite's execution model but are written in slightly different ways. It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. > If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). From 88ca25bdc2e5e2f223f68a5e8ee750d036441493 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:43:41 +0100 Subject: [PATCH 24/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index eddb1d9c0..611fa74d6 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -6,7 +6,7 @@ This document is part of the Appwrite contributors' guide. Before you continue r Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's serverless functions! Appwrite's goal is to support as many function runtimes as possible. ## 1. Prerequisites -In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works. Theses are as follows: +In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works: - [ ] The Language in question must be able to run a web server that can serve JSON and text. - [ ] The Runtime must be able to be packaged into a Docker container From 716243656b5e64c804b7b253806750bd82014d5a Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 12 Oct 2021 09:43:47 +0100 Subject: [PATCH 25/27] Update docs/tutorials/add-runtime.md Co-authored-by: kodumbeats --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 611fa74d6..382f0a49d 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -3,7 +3,7 @@ This document is part of the Appwrite contributors' guide. Before you continue reading this document make sure you have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/master/CODE_OF_CONDUCT.md) and the [Contributing Guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). ## Getting started -Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's serverless functions! Appwrite's goal is to support as many function runtimes as possible. +Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's Cloud Functions! Appwrite's goal is to support as many function runtimes as possible. ## 1. Prerequisites In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works: From ff113cf25ec735ad65191b8b188c9ffe729eb090 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Tue, 19 Oct 2021 09:21:39 +0100 Subject: [PATCH 26/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 382f0a49d..386add5b8 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -150,7 +150,7 @@ docker build -t dart-runtime:2.12 ./runtimes/dart-2.12 Next open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross platform compiles and deploying it to docker hub. The following is an example also with dart version 2.12: ``` echo 'Dart 2.12...' -docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/386 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push +docker buildx build --platform linux/amd64,linux/arm64 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push ``` ## 4. Adding the runtime to the runtimes list From f2cf8db3da22922767288c9c7b335d851e065d98 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Thu, 21 Oct 2021 10:58:19 +0100 Subject: [PATCH 27/27] Update add-runtime.md --- docs/tutorials/add-runtime.md | 100 +++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/docs/tutorials/add-runtime.md b/docs/tutorials/add-runtime.md index 386add5b8..023b53294 100644 --- a/docs/tutorials/add-runtime.md +++ b/docs/tutorials/add-runtime.md @@ -6,14 +6,14 @@ This document is part of the Appwrite contributors' guide. Before you continue r Function Runtimes allow you to execute code written in any language and form the basis of Appwrite's Cloud Functions! Appwrite's goal is to support as many function runtimes as possible. ## 1. Prerequisites -In order for a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works: +For a function runtime to work, two prerequisites **must** be met due to the way Appwrite's Runtime Execution Model works: - [ ] The Language in question must be able to run a web server that can serve JSON and text. - [ ] The Runtime must be able to be packaged into a Docker container Note: Both Compiled and Interpreted languages work with Appwrite's execution model but are written in slightly different ways. -It's really easy to contribute to an open source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your own local version of Appwrite, where you can make any changes without affecting Appwrite right away. +It's really easy to contribute to an open-source project, but when using GitHub, there are a few steps we need to follow. This section will take you step-by-step through the process of preparing your local version of Appwrite, where you can make any changes without affecting Appwrite right away. > If you are experienced with GitHub or have made a pull request before, you can skip to [Implement new runtime](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/add-runtime.md#2-implement-new-runtime). ### 1.1 Fork the Appwrite repository @@ -22,19 +22,19 @@ Before making any changes, you will need to fork Appwrite's repository to keep b [![Fork button](https://github.com/appwrite/appwrite/raw/master/docs/tutorials/images/fork.png)](https://github.com/appwrite/appwrite/blob/master/docs/tutorials/images/fork.png) -This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using `git clone` command: +This will redirect you from `github.com/appwrite/php-runtimes` to `github.com/YOUR_USERNAME/php-runtimes`, meaning all changes you do are only done inside your repository. Once you are there, click the highlighted `Code` button, copy the URL and clone the repository to your computer using the `git clone` command: ```bash $ git clone COPIED_URL ``` -> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a really clean and simple visual Git client. +> To fork a repository, you will need a basic understanding of CLI and git-cli binaries installed. If you are a beginner, we recommend you to use `Github Desktop`. It is a clean and simple visual Git client. Finally, you will need to create a `feat-XXX-YYY-runtime` branch based on the `refactor` branch and switch to it. The `XXX` should represent the issue ID and `YYY` the runtime name. ## 2. Implement new runtime ### 2.1 Preparing the files for your new runtime -The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance if I was to write a Rust Runtime with the version 1.55 the folder name would be: `rust-1.55` +The first step to writing a new runtime is to create a folder within `/runtimes` with the name of the runtime and the version separated by a dash. For instance, if I was to write a Rust Runtime with version 1.55 the folder name would be: `rust-1.55` Within that folder you will need to create a few basic files that all Appwrite runtimes require: ``` @@ -49,11 +49,11 @@ Interpreted languages have both a `build.sh` file and a `launch.sh` file. The `build.sh` file for an interpreted runtime is normally used for installing any dependencies for both the server itself and the user's code and then to copy it to the `/usr/code` folder which is then packaged and can be used later for running the server. The build script is always executed during the build stage of tag deployment. -The `launch.sh` file for a interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. +The `launch.sh` file for an interpreted runtime should extract the `/tmp/code.tar.gz` file that contains both the user's code and the dependencies. This tarball was created by Appwrite from the `/usr/code` folder and should install the dependencies that were pre-installed by the build stage and move them into the relevant locations for that runtime. It will then run the server ready for execution. --- Compiled Languages only have a `build.sh` file. -The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` in order for the ubuntu or alpine images to detect and run them. +The `build.sh` script for a compiled runtime is used to move the user's source code and rename it into source files for the runtime (The `APPWRITE_ENTRYPOINT_NAME` environment variable can help with this) it will also build the code and move it into the `/usr/code` folder. Compiled runtime executables **must** be called `runtime` for the ubuntu or alpine images to detect and run them. #### Note: `/tmp/code.tar.gz` is always created from the `/usr/code` folder in the build stage. If you need any files for either compiled or interpreted runtimes you should place them there and extract them from the `/tmp/code.tar.gz` during the `launch.sh` script to get the files you need. @@ -62,42 +62,42 @@ The `build.sh` script for a compiled runtime is used to move the user's source c Internally the runtime can be anything you like as long as it follows the standards set by the other runtimes. The best way to go about writing a runtime is like so: -Initialize a web server which runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following: -1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and a `unauthorized` error message. +Initialize a web server that runs on port 3000 and uses any IP Address (0.0.0.0) and on each `POST` request do the following: +1. Check that the `x-internal-challenge` header matches the `APPWRITE_INTERNAL_RUNTIME_KEY` environment variable. If not return an error with a `401` status code and an `unauthorized` error message. 2. Decode the executor's JSON POST request. This normally looks like so: ```json { "path": "/usr/code", "file": "index.js", "env": { - "hello":"world!" - }, + "hello":"world!" + }, "payload":"An Example Payload", "timeout": 10 } ``` For a compiled language you can disregard the `path` and `file` attribute if you like, -`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise it doesn't matter since the connection will simply be dropped by the executor. +`timeout` is also an optional parameter to deal with, if you can handle it please do. Otherwise, it doesn't matter since the connection will simply be dropped by the executor. You must create two classes for users to use within their scripts. A `Request` Class and a `Response` class The `Request` class must store `env`, `payload` and `headers` and pass them to the user's function. -Request always goes before response in the user's function parameters. +The Request always goes before the response in the user's function parameters. The `Response` class must have two functions. - A `send(string)` function which will return text to the request - and a `json(object)` function which will return JSON to the request setting the appropriate headers -For a interpreted language use the `path` and `file` parameters to find the file and require it. -Please make sure to add appropriate checks to make sure the imported file is actually a function that you can execute. +For interpreted languages use the `path` and `file` parameters to find the file and require it. +Please make sure to add appropriate checks to make sure the imported file is a function that you can execute. -5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return then cleanly to the executor with the error schema. +5. Finally execute the function and handle whatever response the user's code returns. Try to wrap the function into a `try catch` statement to handle any errors the user's function encounters and return them cleanly to the executor with the error schema. ### 2.4 The Error Schema All errors that occur during the execution of a user's function **MUST** be returned using this JSON Object otherwise Appwrite will be unable to parse them for the user. ```json { - "code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed. - "message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user. + "code": 500, // (Int) Use 404 if function not found or use 401 if the x-internal-challenge check failed. + "message": "Error: Tried to divide by 0 \n /usr/code/index.js:80:7", // (String) Try to return a stacktrace and detailed error message if possible. This is shown to the user. } ``` @@ -108,17 +108,31 @@ The first thing you need to do is find a docker image to base your runtime off, Next in your Dockerfile at the start add the docker image you want to base it off at the top like so: ```bash -FROM Dart:2.12 # Dart used as an example. +FROM Dart:2.12 # Dart is used as an example. ``` This will download and require the image when you build your runtime and allow you to use the toolset of the language you are building a runtime for. -Next copy your source code and set the work directory for the image like so: +Create a user and group for the runtime, this user will be used to both build and run the code: +```bash +RUN groupadd -g 2000 appwrite \ +&& useradd -m -u 2001 -g appwrite appwrite +``` + +then create the folders you will use in your build step: +```bash +RUN mkdir -p /usr/local/src/ +RUN mkdir -p /usr/code +RUN mkdir -p /usr/workspace +RUN mkdir -p /usr/builtCode +``` + +Next copy your source code and set the working directory for the image like so: ``` WORKDIR /usr/local/src COPY . /usr/local/src ``` -Next you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so: +Next, you want to make sure you are adding execute permissions to any scripts you may run, the main ones are `build.sh` and `launch.sh`. You can run commands in Dockerfile's using the `RUN` prefix like so: ``` RUN chmod +x ./build.sh RUN chmod +x ./launch.sh @@ -127,7 +141,15 @@ Note: Do not chmod a `launch.sh` file if you don't have one. If needed use the `RUN` commands to install any dependencies you require for the build stage. -Finally you'll add a `CMD` command. For a interpreted language this should be: +Next set the permissions for the user you created so your build and run step will have access to them: +``` +RUN ["chown", "-R", "appwrite:appwrite", "/usr/local/src"] +RUN ["chown", "-R", "appwrite:appwrite", "/usr/code"] +RUN ["chown", "-R", "appwrite:appwrite", "/usr/workspace"] +RUN ["chown", "-R", "appwrite:appwrite", "/usr/builtCode"] +``` + +Finally, you'll add a `CMD` command. For an interpreted language this should be: ``` CMD ["/usr/local/src/launch.sh"] ``` @@ -139,7 +161,7 @@ CMD ["tail", "-f", "/dev/null"] ``` so the build steps can be run. -## 3. Building your docker image and adding it to the list +## 3. Building your Docker image and adding it to the list With your runtime successfully created you can now move on to building your docker image and adding it to the script files used for generating all of the image files. Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to it. The following is an example with dart version 2.12 @@ -147,7 +169,7 @@ Open up the `/runtimes/buildLocalOnly.sh` script first and add your runtime to i echo 'Dart 2.12...' docker build -t dart-runtime:2.12 ./runtimes/dart-2.12 ``` -Next open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross platform compiles and deploying it to docker hub. The following is an example also with dart version 2.12: +Next, open up the `/runtimes/build.sh` script and also add your runtime to it. This one is slightly different as this is the one that will be used for cross-platform compiles and deploying it to Docker hub. The following is an example also with dart version 2.12: ``` echo 'Dart 2.12...' docker buildx build --platform linux/amd64,linux/arm64 -t dart-runtime:2.12 ./runtimes/dart-2.12/ --push @@ -169,7 +191,7 @@ The second line adds a new version to the language entry, I'll break down the pa 1: Version - The version of the runtime you are creating. 2: Build Image - The image used to build the code 3: Run Image - The image used to run the code. -For interpreted languages this is normally the same as the Build Image, but for compiled languages this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" +For interpreted languages, this is normally the same as the Build Image, but for compiled languages, this can be either "appwrite-alpine:3.13.6" or "appwrite-ubuntu:20.04" We recommend using Alpine when possible and using Ubuntu if the runtime doesn't work on Alpine. 4: Platforms Supported - These are the architectures this runtime is available to. ``` @@ -178,26 +200,26 @@ The third line simply adds the new runtime to the main list. ## 5. Adding tests ### 5.1 Writing your test execution script -Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for, as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema: +Adding tests for your runtime is simple, go into the `/tests/resources` folder and create a folder for the language you are creating then within the folder create a source code file for the language you are writing a runtime for as if you were creating a user function for your runtime. Within this user function you are writing all you need to do is return some JSON with the following schema: ```json { - "normal": "Hello World!", - "env1": request.env['ENV1'], // ENV1 from the request environment variable - "payload": request.payload, // Payload from the request + "normal": "Hello World!", + "env1": request.env['ENV1'], // ENV1 from the request environment variable + "payload": request.payload, // Payload from the request } ``` ### 5.2 Creating the test packaging script for your runtime With your test execution written you can move on to writing the script used to package your test execution script into a tarball for later use by the test system. Move into `/test/resources` again and notice how we have shell scripts for all runtimes we have made tests for. -Go ahead and create a shell script yourself with your language name. As an example the shell script name for dart would be `package-dart.sh` +Next create a shell script yourself with your language name. As an example, the shell script name for dart would be `package-dart.sh` -Within this newly created script copy paste this script and replace all the `LANGUAGE_NAME` parts with your language's name +Within this newly created script copy-paste this script and replace all the `LANGUAGE_NAME` parts with your language's name ``` echo 'LANGUAGE_NAME Packaging...' rm $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz tar -zcvf $(pwd)/tests/resources/LANGUAGE_NAME.tar.gz -C $(pwd)/tests/resources/LANGUAGE_NAME . ``` -Go ahead and save this file. Then `cd` into the root of the `php-runtimes` project in a terminal. Go ahead and run the following command replacing the `LANGUAGE_NAME` with your language's name: +Then save this file. Then `cd` into the root of the `php-runtimes` project in a terminal. Run the following command replacing the `LANGUAGE_NAME` with your language's name: ``` chmod +x ./tests/resources/package-LANGUAGE_NAME.sh && ./tests/resources/package-LANGUAGE_NAME.sh ``` @@ -206,16 +228,16 @@ This command adds execution permissions to your script and executes it. NOTE: If you ever want to repackage your script you can simply run: `./tests/resources/package-LANGUAGE_NAME.sh` in the root of the `php-runtimes` project since you don't have to change permissions more than once. ### 5.3 Adding your runtime to the main testing script -Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Go ahead and open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. +Now you have created your test execution script and have packaged it up for your runtime to execute you can now add it to the main testing script. Open up the `./tests/Runtimes/RuntimesTest.php` file and find the part where we are defining `$this->tests`. -Once you have found this, go ahead and add your own entry into this array like so: +Once you have found this, Add your own entry into this array like so: ```php 'LANGUAGE_NAME-VERSION' => [ - 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', - 'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME - 'timeout' => 15, - 'runtime' => 'LANGUAGE_NAME-VERSION', - 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. + 'code' => $functionsDir . ' /LANGUAGE_NAME.tar.gz', + 'entrypoint' => 'Test file', // Replace with the name of the test file you wrote in ./tests/resources/LANGUAGE_NAME + 'timeout' => 15, + 'runtime' => 'LANGUAGE_NAME-VERSION', + 'tarname' => 'LANGUAGE_NAME-VERSION.tar.gz', // Note: If your version has a point in it replace it with a dash instead for this value. ], ``` Make sure to replace all instances of `LANGUAGE_NAME` with your language's name and `VERSION` with your runtime's version.