├── .github └── workflows │ ├── linter.yml │ ├── pull_request.yml │ └── push.yml ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── logo.svg └── planttree.py /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-python@v2 11 | - uses: psf/black@master 12 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Example Integration on Pull Request 2 | on: 3 | pull_request_target: 4 | branches: 5 | - main 6 | types: 7 | - closed 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Plant a Tree 13 | if: github.event.pull_request.merged == true 14 | id: planttree 15 | uses: protontypes/continuous-reforestation@main 16 | with: 17 | # Enter your API variables below 18 | apikey: ${{ secrets.raaskey }} 19 | enterpriseid: "cd7cedcd" 20 | user: ${{ github.actor }} 21 | treecount: 5 22 | projectid: "14442771" # This projectid can be used to have your trees planted where they are needed the most. 23 | production: "false" 24 | 25 | - name: Response of digitalhumani.com RaaS API 26 | run: | 27 | echo "${{ steps.planttree.outputs.response }}" 28 | echo "${{ steps.planttree.outputs.plantedTrees }}" 29 | -------------------------------------------------------------------------------- /.github/workflows/push.yml: -------------------------------------------------------------------------------- 1 | name: Plant a tree on every push to main 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | plantrees: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Plant a Tree 11 | id: planttrees 12 | uses: protontypes/continuous-reforestation@main 13 | with: 14 | # Enter your API variables below 15 | apikey: ${{ secrets.raaskey }} 16 | enterpriseid: "cd7cedcd" 17 | user: ${{ github.actor }} 18 | treecount: 1 19 | projectid: "14442771" # This projectid can be used to have your trees planted where they are needed the most, so this is a great ID to use by default when making the API call. 20 | production: "false" 21 | 22 | - name: Response of digitalhumani.com RaaS API 23 | run: | 24 | echo "${{ steps.planttrees.outputs.response }}" 25 | echo "${{ steps.planttrees.outputs.plantedTrees }}" 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-slim AS builder 2 | ADD . /app 3 | WORKDIR /app 4 | 5 | # We are installing a dependency here directly into our app source dir 6 | RUN pip install --target=/app requests 7 | 8 | # A distroless container image with Python and some basics like SSL certificates 9 | # https://github.com/GoogleContainerTools/distroless 10 | FROM gcr.io/distroless/python3-debian10 11 | COPY --from=builder /app /app 12 | WORKDIR /app 13 | ENV PYTHONPATH /app 14 | CMD ["/app/planttree.py"] 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 protontypes and contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Continuous Reforestation 2 | **Make tree planting a part of your daily workflow. :deciduous_tree:** 3 | 4 | [](https://github.com/protontypes/continuous-reforestation) 5 | A GitHub Action for planting trees within your development workflow using the Reforestation as a Service (RaaS) API developed by [DigitalHumani](https://digitalhumani.com/). 6 | 7 | Planting trees is an easy way to make a difference in the fight against climate change. Every tree helps to bind CO2 as long as it grows and creates living space for wildlife. Automating the process gives you total control of where, when and how much you want to contribute while saving you the fuss of doing the whole process manually. By using the RaaS API, you or your project can plant trees in a transparent way by exposing the API calls and related statistics. The RaaS API is completely free of charge. You only pay for the trees (1 $ each) directly to the reforestation organization. Find more information on this project read our [blog post](https://protontypes.eu/blog/2021/03/25/continuous-reforestation/).

8 | [![Actions Status](https://github.com/protontypes/continuous-reforestation/workflows/Lint/badge.svg)](https://github.com/jacobtomlinson/protontypes/continuous-reforestation/actions) 9 | [![Actions Status](https://github.com/protontypes/continuous-reforestation/workflows/Integration%20Test/badge.svg)](https://github.com/protontypes/continuous-reforestation/actions) 10 | [![](https://badgen.net/badge/icon/Community%20Chat/green?icon=gitter&label)](https://gitter.im/protontypes/community) 11 | 12 | ## Use cases 13 | Plant trees on ... 14 | * pull requests (and/or push, ...). 15 | * failed or successful tests. 16 | * the very first contribution to an open source project. 17 | * a new release, a milestone, or a closed issue. 18 | * a scheduled event (i.e. once per week). 19 | * the carbon footprint of your digital products after deployment. 20 | 21 | See more possible trigger events [here](https://docs.github.com/en/actions/reference/events-that-trigger-workflows). 22 | 23 | ## Usage 24 | 25 | 1. 🏁 To get started, you need an account with DigitalHumani RaaS. Since they are currently in the early stages, you have to contact them to get an account. Send them an email [here](https://digitalhumani.com/#contact). You also receive the API key value corresponding for your enterprise ID. This is your secret authentication key. **Do not add your API key to your workfile yaml file**. 26 | 27 | 2. ✂️ Copy the example worflow to `/.github/workflow/integration.yaml` and change the variables in the workflow to your data. Set the `production` variable to `false` to test your implementation within the sandboxed development API. Push your script to GitHub and check the GitHub Action tab of your project. If you use GitHub Action for the first time, activate it when prompted. 28 | 29 | 3. 📈 An open dashboard is provided to ensure a high level of transparency. This is currently under development and will show additional details. For this purpose visit: 30 | `` 31 | https://digitalhumani.com/dashboard/ 32 | `` 33 | 34 | 4. 🗝️ Add your authentication key as a secret in your repository `Settings` -> `Secrets` -> `New Repository Secret`: Name: `RAASKEY`, Value: ``. You can also add it as an organization wide secret in the setting of your organization. 35 | 36 | 5. 🌱 Verify the number of trees planted in the dashboard development statistics. Set the `production` variable to `true` and push this commit. You now have left the development environment and started planting trees. From now on every configured trigger will continuously request to plant trees. At the end of each month you will be asked to confirm your requested amount of trees. 37 | 38 | To see a list of all supported reforestation projects and more details on the RaaS API read the [documentation of DigitalHumani](https://digitalhumani.com/docs/#appendixlist-of-projects). 39 | 40 | **Disclaimer:** Even though this workflow automates the request to plant trees, the planting process itself remains manual labour by the reforestation organisations. They are also the people who write your invoice. Due to the amount of work it requires to write these invoices, DigitalHumani accumulates your plant requests until you reach a certain number, depending on your chosen reforestation project, before issuing the order. Below are the least required amounts to receive a monthly invoice and actually plant trees. If you plant more, don't mind this disclaimer. 41 | 42 | | Reforestation project | Necessary number of requested trees | 43 | | --------------------- | ----------------------------------- | 44 | | Chase Africa | 20 | 45 | | Conserve Natural Forests | 20 | 46 | | OneTreePlanted | 1 | 47 | | Sustainable Harvest International | 50 | 48 | | TIST | 20 | 49 | 50 | ### Example workflows 51 | 52 | ```yaml 53 | name: Plant a tree on a successful merged pull request to your main branch 54 | on: 55 | pull_request_target: 56 | branches: 57 | - main 58 | types: 59 | - closed 60 | jobs: 61 | planttrees: 62 | runs-on: ubuntu-latest 63 | steps: 64 | - name: Plant a Tree 65 | if: github.event.pull_request.merged == true 66 | id: planttrees 67 | uses: protontypes/continuous-reforestation@main 68 | with: 69 | # Enter your API variables below 70 | apikey: ${{ secrets.raaskey }} 71 | enterpriseid: "" 72 | user: ${{ github.actor }} 73 | treecount: 1 74 | projectid: "14442771" # This projectid can be used to have your trees planted where they are needed the most. 75 | production: "true" 76 | 77 | - name: Response of digitalhumani.com RaaS API 78 | run: | 79 | echo "${{ steps.planttrees.outputs.response }}" 80 | ``` 81 | 82 | ```yaml 83 | name: Plant a tree on every push to main 84 | on: 85 | push: 86 | branches: 87 | - main 88 | jobs: 89 | planttrees: 90 | runs-on: ubuntu-latest 91 | steps: 92 | - name: Plant a Tree 93 | id: planttrees 94 | uses: protontypes/continuous-reforestation@main 95 | with: 96 | # Enter your API variables below 97 | apikey: ${{ secrets.raaskey }} 98 | enterpriseid: " 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 54 | 57 | 60 | 64 | 68 | 72 | 73 | 77 | 81 | 85 | 86 | 87 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /planttree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import requests 4 | from urllib.parse import urljoin 5 | import posixpath 6 | import json 7 | import sys 8 | import re 9 | 10 | 11 | def main(): 12 | # Variables set by the CI script 13 | enterprise_id = os.environ["INPUT_ENTERPRISEID"] 14 | project_id = os.environ["INPUT_PROJECTID"] 15 | user = os.environ["INPUT_USER"] 16 | treecount = int(os.environ["INPUT_TREECOUNT"]) 17 | production = os.environ["INPUT_PRODUCTION"] 18 | api_key = os.environ["INPUT_APIKEY"] 19 | 20 | # REST API Parameters 21 | body_para = { 22 | "treeCount": treecount, 23 | "enterpriseId": enterprise_id, 24 | "projectId": project_id, 25 | "user": user, 26 | } 27 | headers = {"x-api-key": api_key} 28 | 29 | # Check of we run in development or production mode 30 | # Using the sandbox API does not require any API key 31 | if production == "true": 32 | print("Using production API") 33 | url = "https://api.digitalhumani.com/tree" 34 | url_numtrees = ( 35 | "https://api.digitalhumani.com/enterprise/" 36 | + enterprise_id 37 | + "/treeCount?startDate=2010-03-01&endDate=2030-01-01" 38 | ) 39 | 40 | else: 41 | print("Using sandbox API for development") 42 | url = "https://api-dev.digitalhumani.com/tree" 43 | url_numtrees = ( 44 | "https://api-dev.digitalhumani.com/enterprise/" 45 | + enterprise_id 46 | + "/treeCount?startDate=2010-03-01&endDate=2030-01-01" 47 | ) 48 | 49 | # run the RaaS requests for planting trees and getting tree count 50 | r = requests.post(url, json=body_para, headers=headers) 51 | r_numtrees = requests.get(url_numtrees, headers=headers) 52 | 53 | # put the response into a dictionary 54 | response = json.loads(r.text) 55 | response_alltrees = json.loads(r_numtrees.text) 56 | response_alltrees = str(response_alltrees) 57 | num_alltrees = re.findall("[0-9]+", response_alltrees) 58 | plantedTrees = num_alltrees[0] 59 | 60 | # create a simple human readable response message 61 | if r.status_code == requests.codes.ok: 62 | print( 63 | "Request successful\n" 64 | + str(response["user"]) 65 | + " planted " 66 | + str(response["treeCount"]) 67 | + " tree(s). " 68 | + "Find more information on dashboard: " 69 | + "https://digitalhumani.com/dashboard/" 70 | + str(enterprise_id) 71 | + ".html\n" 72 | + plantedTrees 73 | + " were now planted in total." 74 | ) 75 | else: 76 | print("Something went wrong. \n Your error code is: " + str(r.status_code)) 77 | sys.exit(1) 78 | 79 | # return the dict to the CI script for following data processing 80 | print(f"::set-output name=response::{response}") 81 | print(f"::set-output name=response::{plantedTrees}") 82 | 83 | 84 | if __name__ == "__main__": 85 | main() 86 | --------------------------------------------------------------------------------