{"id":19092856,"url":"https://github.com/eon01/python-ci-example","last_synced_at":"2026-06-20T22:31:09.990Z","repository":{"id":74328603,"uuid":"113914708","full_name":"eon01/python-ci-example","owner":"eon01","description":null,"archived":false,"fork":false,"pushed_at":"2017-12-12T05:12:34.000Z","size":257,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-22T07:46:14.466Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eon01.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-11T22:19:30.000Z","updated_at":"2019-01-31T00:59:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"d71bf464-5d3e-439a-bfa3-a7ee538f7f6c","html_url":"https://github.com/eon01/python-ci-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eon01/python-ci-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2Fpython-ci-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2Fpython-ci-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2Fpython-ci-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2Fpython-ci-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eon01","download_url":"https://codeload.github.com/eon01/python-ci-example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eon01%2Fpython-ci-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":283943917,"owners_count":26920581,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-11T02:00:06.610Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T03:22:24.268Z","updated_at":"2025-11-11T22:33:17.511Z","avatar_url":"https://github.com/eon01.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introduction\n\n\n\nContinuous integration (CI) is one of the Agile and DevOps software development practices. It helps development teams avoid  merge conflicts by setting up a continuous merging of new code updates into a shared central repository.\n\nAutomating the build and testing of code each time one of your team members commit a change to your version control is one of the best practices in DevOps. This practice adds the \"fail-fast\" paradigm for your application development and an iterative development approach.\n\nContinuous integration is about delivering small chunk of code continuously which improves a development team productivity and helps them fix bugs quickly before the release and deployment phases.\n\n\nThere are several CI tools like Jenkins, Buildbot, TravisCI, GoCD and Team Foundation Server.\n\n# Preparing Our Application\n\nIn this practice lab, we are going to work on a Python project. The purpose of this lab is creating a system that trigger a list of tasks once a developer push a code to a share code repository. \n\nWe are going to use:\n\n- Python 3.5\n- Python Virtualenv to create an isolated environment for our application\n- Unittest: A unit testing framework for Python\n- Github: A web-based Git version control repository hosting service\n- CircleCI: A hosted continuous integration testing tool integrated with code management services such as GitHub\n\nThis is the structure of our code:\n\n```\n\napp/\n├── __init__.py\n├── src\n│   ├── app.py\n│   ├── __init__.py\n└── tests\n    ├── app-test.py\n    └── __init__.py\n.gitignore\n.travisci\n__init__.py\nREADME.md    \n```\n\nWhere app.py is the source of our application, app-test.py is the test case and all of the \\__init\\__.py files are empty.\n\nYou can also download the .gitignore file from [this repository](https://github.com/github/gitignore/blob/master/Python.gitignore).\n\nYou can use Python Virtualenv and create an isolated environment. You can download virtualenv source from [here](https://pypi.python.org/pypi/virtualenv) and execute the setup.py script to install it. To activate your virtual environment execute:\n\n\n```\npython3 -m venv /path/to/new/virtual/environment\n```\n\nIf you are using Linux.\n\n```\nc:\\\u003ec:\\Python35\\python -m venv c:\\path\\to\\myenv\n```\n\nIf you are using Windows.\n\nIf everything is fine, let's activate it:\n\n```\n. /path/to/new/virtual/environment/bin/activate\n```\n\nOur app.py is a simple application that returns the sum of two numbers:\n\n```\ndef my_function(param1, param2):\n    return param1 + param2   \n```\n\n# Unit Testing\n\nIn order to test our application, we are going to write our a test scenario using Python unittest (tests/app-test.py):\n\n```\nimport unittest\nfrom app.src.app import my_function\n\n\nclass MyTest(unittest.TestCase):\n    def test_my_function(self):\n        self.assertEqual(my_function(1, 1), 2)\n        self.assertEqual(my_function(1, -1), 0)\n        self.assertEqual(my_function(0, 0), 0)\n        self.assertEqual(my_function(-1, -1), -2)\n        self.assertEqual(my_function(1.0, 1), 2)        \n        self.assertEqual(my_function(1.1, 1.1), 2.2)        \n        \n        \n        \nif __name__ == '__main__':\n    unittest.main()        \n```\n\nIn the previous test code, we tested different scenarios like summing up two negative integers or two floats. It is a good practice to think about the best possible scenarios and implement the suitable test cases in order to reduce the number of bugs.\n\nYou can execute this test case using the following command:\n\n```\npython app/tests/app-test.py \n```\n\nIf tests run without any problem you should see:\n\n```\n.\n----------------------------------------------------------------------\nRan 1 test in 0.000s\n\nOK\n```\n\nIf you have one or more problems with your test assertions, the test will not pass.\n\nFor example:\n\n```\nimport unittest\nfrom app.src.app import my_function\n\n\nclass MyTest(unittest.TestCase):\n    def test_my_function(self):\n        # 1 + 1 = 4\n        self.assertEqual(my_function(1, 1), 4)\n        \n        \n        \nif __name__ == '__main__':\n    unittest.main()        \n```\n\nThe output of the test execution will be similar to the following:\n\n```\nF\n======================================================================\nFAIL: test_my_function (__main__.MyTest)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n  File \"app/tests/app-test.py\", line 7, in test_my_function\n    self.assertEqual(my_function(1, 1), 4)\nAssertionError: 2 != 4\n\n----------------------------------------------------------------------\nRan 1 test in 0.001s\n\nFAILED (failures=1)\n```\n\n# Dependencies\n\nWhen you use a programming language to develop your application, you usually need to install libraries. This is the case for Python and that's why we need to declare our dependencies. This is done in the requirements.txt file using this command:\n\n```\npip freeze \u003e requirements.txt\n```\n\nIn this project, we are not using any additional library, that's why our requirements.txt will be empty but always remember this step.\n\nIn order to integrate the Travis CI workflow, we should create the configuration file (.travis.yml). \nThis file will tell Travis CI \n\n\n\nYou can customize your build environment and add the set of steps in this file. \n\nTravis CI uses .travis.yml file in the root of your repository to learn about your project environment, how you want your builds to be executed, what kind of tests to perform and other information like emails, Campfire and IRC rooms to notify about build failures.\n\nThis is the file we are going to use:\n\n```\nlanguage: python\npython:\n  - \"3.5\"\n# command to install dependencies\ninstall:\n  - pip install -r requirements.txt\n# command to run tests\nscript:\n  - export PYTHONPATH=$PYTHONPATH:$(pwd)\n  - python app/tests/app-test.py\n```\n\n# Setup Our Git\n\nNow that we finished writing our code, the .gitignore file, the test and the Travis CI configuration, we need to create a Github repository and link our Travis CI to our Github account in order to import the new project.\n\n\n```\ngit init\ngit add .\ngit commit -m \"First commit\"\ngit remote add origin \u003cremote repository URL\u003e\ngit push origin master\n```\n\nDon't forget to change  the \u003cremote repository URL\u003e by its real value, you can get it from your Github repository:\n\n![repository URL](images/url.png \"repository URL\")\n\n# Setup Travis CI\n\nGo to your Travis CI dashboard, connect your Github account then sync your repositories and add the new project. This will generate your first build and you can see whether your build passes or no.\n\n![Build History ](images/buids.png \"Build History\")\n\nAfter every code commit, a build will start automatically and you will be notified by email on its status.\n\n\n# Managing Pull Requests\n\nNow, if your are working on a different branch than the master, which is the case for all development teams, you need to make a pull request then merge your code. Let's try to test this:\n\nCreate the branch \"dev\" on your local machine:\n\n```\ngit checkout -b dev\n```\n\nAdd your modifications then push them to the dev branch:\n\n```\ngit push origin dev\n```\n\nOnce your modifications are added to the remote dev branch, Circle CI will trigger a new build for the dev branch and you will notice that you can make a pull request on the master branch:\n\n![Git Pull Request](images/pull.png \"Git Pull Request\")\n\nIf the pull request is accepted an merged with the master branch, our CI tool will trigger a new build under the \"Pull Requests\" tab:\n\n![Circle CI Pull Request Build](images/pr.png \"Circle CI Pull Request Build\")\n\n\n\n# Conclusion\n\nDuring this practice lab, we created an application using Python using Virtualenv for the environment isolation then we created a Github repository for this application and linked it to our Travis CI account.\n\nThe continuous build and test were described in our .travis.yml file. \n\nIt is possible to add more advanced features like ChatOps using Slack, IRC or any alternative, add more steps to your integration pipeline like creating a Docker image or deploying to a Azure Web App.. etc\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feon01%2Fpython-ci-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feon01%2Fpython-ci-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feon01%2Fpython-ci-example/lists"}