How I made a GitHub action to host coding competition on GitHub!
Tags: github, python, docker, testing
Published: 2020-04-16 09:09:42

<p align="center">
   <img src="https://dev-to-uploads.s3.amazonaws.com/i/2gc7ug6tbaq713at11ng.png" alt="Strivio Logo"/>
</p>

# Strivio
Strivio is a GitHub action that allows anyone to host competitive coding event directly on GitHub Repository like hackerrank, leetcode, etc. It is fun to use and quite simple. It also has the support of many programming languages such as `c` , `c++`, `java` and `python`
You can check **Strivio** here on the GitHub marketplace.
[https://github.com/marketplace/actions/strivio](https://github.com/marketplace/actions/strivio)
Strivio is also OpenSourced on GitHub and here are the links for the action and the source code of the action.
`Action Repo` - [https://github.com/jainal09/strivio](https://github.com/jainal09/strivio)
`Source Code`- [https://github.com/jainal09/strivio-docker](https://github.com/jainal09/strivio-docker)
Also, check out the `docker image on docker hub`- https://hub.docker.com/r/jainal09/strivio
## Introduction
Ever wondered that is it possible to host a competitive coding event on GitHub?
Well, it should be possible given the fact that GitHub provides CI / CD built-in through **GitHub Action**.
So, I decided wouldn't it be cool if I make a GitHub action that simply tests code by passing given sets of Inputs and checking it against given sets of outputs. Sounds simple right? Well, it's a kind of little complex! 

![enter image description here](https://media.giphy.com/media/dWy2WwcB3wvX8QA1Iu/giphy.gif)
You see, there are a few **challenges** I need to solve.
- Input and output test cases should be hidden somewhere and the participants of the events cannot see it.
- Multiple Programming Language Support
- And a system that should enable organizers to use the action without modifying the code.
- One GitHub action that can be used simultaneously many people around the world.

***So, this is how it all went.***

![enter image description here](https://media.giphy.com/media/xT9Igz4cFb1K91fTI4/giphy.gif)
## Idea Construction
So basically I created a rough idea of implementation like this:

`my-python-script` ------> `user-code` ------> `compile and run` ------> `result`

So, here first my python script identifies users' programming language. Then it compiles and runs the user's program by passing necessary inputs and storing outputs.
It then matches the outputs of the program with the output of the test cases. If all outputs are passed than tick
☑️ and if not than ✖️.

## Solving Challenges
So, I thought if there is a way that input test cases **magically appeared** at run time and disappeared after that should solve my issue.

![enter image description here](https://media.giphy.com/media/3o7TKP9ln2Dr6ze6f6/giphy.gif)

Hence, I used an amazing bash script known as the DropBox uploader.
https://github.com/andreafabrizi/Dropbox-Uploader
What it does is it allows anyone to download and upload files from their DropBox account from the terminal!
Sounds cool right. It also has many more cool features and I recommend you to have a look at this repository.
So, now organizers will simply upload input and output test cases on their DropBox drive and during the run time my script will download the input and output test cases through a unique token(dropbox API key) preventing visibility to the participants.
This solved my 2 challenges.

~~Input and output test cases should be hidden somewhere and the participants of the events cannot see it.~~

~~And a system that should enable organizers to use the action without modifying the code.~~

Still, 2 challenges needed to solve.
For multiple language support, I decided to stick it to simple and restrict the top 4 most popular competetive coding programming languages i.e python, java, cpp, and c.
![enter image description here](https://media.giphy.com/media/3OvvA11fPUvfYRFjxS/giphy.gif)

 The support to the programming languages can be solved by using docker with all the dependencies and compilers installed into a docker container.

~~Multiple Programming Language Support~~

![enter image description here](https://www.mememaker.net/api/bucket?path=static/img/memes/full/2017/Jan/30/23/docker-docker-everywhere.jpg)

And the last issue, allowing simultaneous use of action was solved by putting the DropBox API key as a GitHub secret and hence not hardcoding it in the code and hence anyone can use the action!

~~One GitHub action that can be used simultaneously many people around the world.~~

***And that's how I solved all my challenges and issues.***
![enter image description here](https://media.giphy.com/media/IelxugxenjdyU/giphy.gif)
## Creating the action
So far the idea was clear to me and the challenges were so far sorted out.

    Now it was coding time!

![enter image description here](https://media.giphy.com/media/LmNwrBhejkK9EFP504/giphy.gif)
As mentioned earlier I needed a python script which I will compile the code for me and a docker container.
Here Is the basic code segment from my Code : [https://github.com/jainal09/strivio-docker/blob/master/Evaluate.py](https://github.com/jainal09/strivio-docker/blob/master/Evaluate.py)
Organizers will upload a I/O test cases and then I will download it and create into python arrays `inputs` and `outputs`. Then I will iterate them and compile and pass inputs and compare outputs. Check out the below code. 
```python
for inp, outp in zip(inputs, outputs):
	 data, temp = os.pipe()
	 os.write(temp, bytes(str(inp), "utf-8"))
	 os.close(temp)
	 output = subprocess.check_output(
	     [
	         "python3",
	      os.path.abspath(
	          "program.py"
	      )
	     ],
	     stdin=data
	 )
	 output = output.decode("utf-8")
	 output = re.sub('\s+', '', output)
	 outp = re.sub('\s+', '', str(outp))                        
	 if output == outp:
	     print("Test Case " + str(case) + ": Passed")
	     case = case + 1
	 else:
	     raise Exception(
	         "Test Case " + str(case) + ": Failed"
	     )
```
Done its as simple as that! You can check out the whole code base and other cool stuff which I did here
[https://github.com/jainal09/strivio-docker](https://github.com/jainal09/strivio-docker)
I am not explaining here each and every segment of it as it kind of makes sense right!
## Okay Now How do I use it?
## Organizers

 1. Head to [DropBox](https://www.dropbox.com) Sign In/ Create account and then click on this link
 [DropBox Developer Page](https://www.dropbox.com/developers/apps?_tk=pilot_lp&_ad=topbar4&_camp=myapps)
 
Alternate Link: https://www.dropbox.com/developers/documentation
- Click on App Console
- Click on Create App
- Click Full Dropbox
- Give any name to the app and Click create app
 2. After you Create your Dropbox App click on Generate Access token and Copy it.![enter image description here](https://miro.medium.com/max/938/1*vLvuPuX5n-klKMConAXQug.png)
 
 This token is to be shared with participants. This works as a login access key for the competition.
 
3. Create a File Known as 🗃️ "IO.yaml" for all the Input / Output Test Cases
4. The File should Look like this
```yaml  
inputs:  
  input1:  
    1  
  input2:  
    2  
  input3:  
    3  
  input4:  
    4  
  input5:  
    5  
outputs:  
  output1:  
    2  
  output2:  
    3  
  output3:  
    4  
  output4:  
    5  
  output5:  
    6  
```
5. Head to DropBox, Upload this `IO.yaml` to the **Root Directory** (not into any folder just upload it outside on dropbox) of Drop Box and done 😃!
6. Send the OATH token to participants.

## Participants

1. In GitHub Repo open Settings/Secrets and click on add a Secret
2. The name of the secret should be **OATH** and value should be the access token which the organizer gave you!

Example: 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fjhhwey31m9qsi39c8ju.jpg)

This should look like this.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b3tplygs39q56ciy1ozi.png)

3. Now its time to start coding!  Clone your repo and start working on the problem.

4. Supported Programming Languages `python, java, c++, c`

5. Create a file program.***extension*** - supported extension`.c .cpp .java .py`

NOTE: for **java** Class name should be `Main`

6. After Coding is done create a file in repo 🗃️ **"lang.yaml"**

7.  Add the below code.
```yaml
language:
  python3
``` 

8. Replace the name of Programming Language in the above code as follows.

` python - write python3`
`java - write java`
`c++ - write cpp`
`c - write c`

***No language other than above are supported!***

9. Commit the code and push

10. Head to GitHub and select Actions

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/x3s8uu0sxnlxfhvyhuhi.jpeg)

11. Click on Set up a workflow yourself

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w0ymzgtv3wn3xnorj0lj.png)

12. Delete everything and paste the below code

```yaml
name: Evaluation
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Results
      uses: jainal09/strivio@Production
      with:
        oath: ${{ secrets.oath }}
```
Click on `start-commit`

13. Click on actions

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fqm1eokv52cv37s5xzz8.jpeg)

14. Click on your last commit, click **build**, wait for the **Build jainal09/strivio@Production** to turn green ✔️ and after that  click on Results 🤞

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2k37lu7s64j9eod6hbmx.png)

15. Check if your code passed all the Test Case ✔️ or ❌

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o7tj0l4f6cetpvqk56mj.png)

 *☝️Successful Build with all Test Case Passed🤘.*
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1l03i2nn4ddseveuvray.png)

*☝️Build Failed as Code Didn't Pass all the Test Cases😬.*

Sample Test Repo - https://github.com/jainal09/strivio-in-action

**Done! that's how you can host a coding competition on GitHub like Hackerrank etc** 
![enter image description here](https://media.giphy.com/media/l2JdVptfnCwNTiBvG/giphy.gif)
## What is the tech used here?

 - GitHub (obviously!)
 - GitHub actions
 - Python 
 - Pyaml to parse the yaml files
 - Dropbox-Uploader
 - Docker
 - Docker Hub for Continuous Deployment with my GitHub repo.
 
## Limitation and Future Scopes
As we all know there is nothing perfect in this world.
So does Strivio! As the idea is just a proof of concept and not a competitor to the online coding platforms.
![enter image description here](https://media.giphy.com/media/LOcPt9gfuNOSI/giphy.gif)

**The following are the Limitations of the project:**

 Currently, only 1 question per repo is supported and I am working for more project support.
- I believe that input and output test cases format should be improved and also separated into 2 different **txt** files rather than yaml.
- Timing and space constraint features are not present.
- Testing against complex I/O test cases.

**The following are the Future Scopes of the project:**

 - [ ] Add support for time and space constraints.
 - [ ] Change Input output formats.
 - [ ] And offcourse solve any created issues.