├── src
├── __init__.py
└── arrayPartition1.py
├── runTests.py
├── res
├── howToFork.png
├── githubWebhook1.png
├── githubWebhook2.png
├── jenkinsNewItem.png
├── findTheCloneLink.png
├── jenkinsNewItemConfig.png
├── jenkinsPostbuildJUnit.png
├── jenkinsProjectGitConfig.png
├── jenkinsProjectBuildTrigger.png
└── jenkinsProjectConfigBuild1.png
├── test
└── test.py
├── .gitignore
└── README.md
/src/__init__.py:
--------------------------------------------------------------------------------
1 | # empty
2 |
--------------------------------------------------------------------------------
/runTests.py:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | cd "$(dirname "$0")"
4 | python2.7 test/test.py
5 |
--------------------------------------------------------------------------------
/res/howToFork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/howToFork.png
--------------------------------------------------------------------------------
/res/githubWebhook1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/githubWebhook1.png
--------------------------------------------------------------------------------
/res/githubWebhook2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/githubWebhook2.png
--------------------------------------------------------------------------------
/res/jenkinsNewItem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsNewItem.png
--------------------------------------------------------------------------------
/res/findTheCloneLink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/findTheCloneLink.png
--------------------------------------------------------------------------------
/res/jenkinsNewItemConfig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsNewItemConfig.png
--------------------------------------------------------------------------------
/res/jenkinsPostbuildJUnit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsPostbuildJUnit.png
--------------------------------------------------------------------------------
/res/jenkinsProjectGitConfig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsProjectGitConfig.png
--------------------------------------------------------------------------------
/res/jenkinsProjectBuildTrigger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsProjectBuildTrigger.png
--------------------------------------------------------------------------------
/res/jenkinsProjectConfigBuild1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InsightDataScience/jenkinsTemplate-python/master/res/jenkinsProjectConfigBuild1.png
--------------------------------------------------------------------------------
/src/arrayPartition1.py:
--------------------------------------------------------------------------------
1 | class Solution(object):
2 | def ArrayPairSum(self, nums):
3 | """
4 | :type nums: List[int]
5 | :rtype: int
6 | """
7 |
8 | # your solution here
9 |
10 | return 0
11 |
12 |
--------------------------------------------------------------------------------
/test/test.py:
--------------------------------------------------------------------------------
1 | import unittest, sys, os
2 | sys.path.append(os.path.abspath("./src"))
3 | from arrayPartition1 import Solution
4 |
5 | class TestArrayPartition1(unittest.TestCase):
6 | def setUp(self):
7 | self.sln = Solution()
8 |
9 | def test_basic(self):
10 | self.assertEqual(self.sln.ArrayPairSum([1,4,2,3]), 4)
11 |
12 |
13 | if __name__ == '__main__':
14 | import xmlrunner
15 | unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports'))
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test-reports/
2 |
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | env/
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | .hypothesis/
50 |
51 | # Translations
52 | *.mo
53 | *.pot
54 |
55 | # Django stuff:
56 | *.log
57 | local_settings.py
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # dotenv
85 | .env
86 |
87 | # virtualenv
88 | .venv
89 | venv/
90 | ENV/
91 |
92 | # Spyder project settings
93 | .spyderproject
94 | .spyproject
95 |
96 | # Rope project settings
97 | .ropeproject
98 |
99 | # mkdocs documentation
100 | /site
101 |
102 | # mypy
103 | .mypy_cache/
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jenkinsTemplate-python
2 | A testable Python project for the Jenkins CI workshop @ Insight Data Engineering.
3 |
4 | * [Part 0: Getting Started](#part-0-getting-started)
5 | * [Part 1: Problem Statement](#part-1-problem-statement)
6 | * [Part 2: Implement and Test](#part-2-implement-and-test)
7 | * [Part 3: Jenkins](#part-3-jenkins-continuous-integration)
8 | * [Part 4: Test-Driven Development](#part-4-test-driven-development)
9 |
10 | ----
11 |
12 | ## Part 0: Getting Started
13 |
14 | If you have not set up SSH keys for your github account yet, please follow these links to [Create an SSH Key](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/#generating-a-new-ssh-key)
15 | and to [Associate it with your GitHub account](https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/).
16 |
17 | You will also need python2 with `xmlrunner` installed. After installing python and pip for your local machine, you can install `xmlrunner` with:
18 |
19 | ```bash
20 | pip install xmlrunner
21 | ```
22 |
23 | Or if you have both python3 and python2 installed, you want to install `xmlrunner` for python2:
24 |
25 |
26 | ```bash
27 | pip2 install xmlrunner
28 | ```
29 |
30 | To begin, fork this repo on GitHub *\([image](res/howToFork.png)\)*
31 | then clone it to your local machine by copying the clone link *\([image](res/findTheCloneLink.png)\)*.
32 | Finally, use `git clone` at your shell / command line with the clone link you just copied. The command will look like this:
33 |
34 | ```bash
35 | git clone git@github.com:[MY_USER]/jenkinsTemplate-python.git
36 | ```
37 |
38 |
39 |
40 |
41 |
42 | ## Part 1: Problem Statement
43 |
44 | Given an array of *2n* integers, your task is to group these integers into *n* pairs of integers, say *(a1, b1), (a2, b2), ..., (an, bn)* which makes the sum of *min(ai, bi)* for all *i* from *1* to *n* as large as possible.
45 |
46 | ### Example
47 |
48 | * **Input:** [1,4,3,2]
49 | * **Output:** 4
50 | * **Explanation:** n is 2, and the maximum sum of pairs is 4.
51 |
52 | ### Notes
53 |
54 | * n is a positive integer, which is in the range of [1, 10000].
55 | * All the integers in the array will be in the range of [-10000, 10000].
56 |
57 |
58 |
59 |
60 | ## Part 2: Implement and Test
61 |
62 | Your first job is to implement a working solution that passes the given test. To do so, modify the code in `src/arrayPartition1.py`.
63 |
64 | Testing is performed by calling `./runTests.py` from your shell / command line.
65 |
66 | If you've implemented a correct solution, the output should look like this:
67 |
68 | ```bash
69 | $ ./runTests.py
70 | .
71 | ----------------------------------------------------------------------
72 | Ran 1 test in 0.000s
73 |
74 | OK
75 | ```
76 |
77 |
78 |
79 |
80 | When you're finished and your test passes, be sure to push your changes back up to GitHub. Here is a rough outline of how to do it:
81 |
82 | * `git status` will show you which files have changed or been added
83 | * `git add [FILENAME] ...` will mark specific files to be committed and sent back to github
84 | * `git commit` will commit your changes locally and allow you to describe what changed in your commit message
85 | * `git push` will send your locally committed changes back to GitHub
86 |
87 |
88 |
89 |
90 |
91 | ## Part 3: Jenkins Continuous Integration
92 |
93 | Now that you have a working solution, let's make sure that whenever you change your code and push it back to GitHub, it remains executable and that all of your tests still pass.
94 |
95 | Jenkins is a popular Open Source tool for Continuous Integration and Continuous Delivery. Since we're not working with collaborators or deploying our code to a server yet, we'll be using Jenkins for Continuous Testing alone.
96 |
97 |
98 | As part of this workshop, you should have received an email with your username, password, and link to our internal Jenkins server. Use the link to log in to Jenkins. On the homepage, click the link on the left that says **New Item**
99 | *\([image](res/jenkinsNewItem.png)\)*.
100 |
101 | In the New Item configuration screen, set the name of the project to `[MY_USERNAME]-jenkinsTest`, then click the box underneath titled **Freestyle project**, and finally click **OK** at the bottom of the page *\([image](res/jenkinsNewItemConfig.png)\)*.
102 |
103 | On the project configuration screen, under **Source Code Management**, select the **Git** list item and enter the URL of your github repository page (Note: *not* the git clone URL). This tells Jenkins where it can get your code from (GitHub) and how to do it (using `git clone`) *\([image](res/jenkinsProjectGitConfig.png)\)*.
104 |
105 | To run tests whenever you push changes to GitHub, you'll need to teach Jenkins and GitHub how to communicate with each other. For Jenkins, you'll need to navigate to the **Build Triggers** section and click the checkbox titled "GitHub hook trigger for GITScm polling" *\([image](res/jenkinsProjectBuildTrigger.png)\)*. On the GitHub side, you'll need to go into the project settings and add a new WebHook that points to your Jenkins server. The URL for the WebHook can be found in your email with your Jenkins credentials
106 | *\([image 1](res/githubWebhook1.png),
107 | [image 2](res/githubWebhook2.png)\)*.
108 |
109 | Now that Jenkins knows how and when to get a copy of your code, it needs to know how to test it. Further down the page, you'll find the **Build** section. Click on **Add build step**, then **Execute shell** *\([image](res/jenkinsProjectConfigBuild1.png)\)*. In the command window that appears, type: `./runTests.py`.
110 |
111 | One last thing we can do is teach Jenkins how to interpret our test results, giving us a better dashboard to examine our test results, and test history with some statistics. Under **Post-Build Actions**, click on **Add post-build action**, and select **Publish JUnit test result report**. You'll want to enter `**/test-reports/*.xml` in the *Test report XMLs* field, because that is where your python script prints out its test results *\([image](res/jenkinsPostbuildJUnit.png)\)*.
112 |
113 | Finally, click **Save** at the bottom.
114 |
115 | If all went well, you'll have just set up push-based continuous testing with GitHub and Jenkins. Now let's try it out!
116 |
117 | * Make some small change to your repository,
118 | * commit it,
119 | * push it back up to GitHub,
120 | * Go back to Jenkins to view your project, and
121 | * watch your Project Status page for a new build beginning on its own
122 |
123 | You should very quickly see a new build in the queue, and within a few seconds, the test results should be available.
124 |
125 |
126 |
127 | ## Part 4: Test-Driven Development
128 |
129 | Test-Driven Development (TDD) is a software development process wherein you write test cases for new software requirements, and only afterwards do you improve the software to pass the tests. Let's practice that.
130 |
131 | What happens when you call `sln.ArrayPairSum(['herp', 'derp'])`? How *should* your program behave? It most likely throws an error, but maybe that isn't how you'd like your program to behave.
132 | Let's say you have the requirement that your function return 0 for non-integral arrays. To implement this using a TDD process:
133 |
134 | * create a new test in `test/test.py` that ensures `ArrayPairSum` returns 0 when it is called with a string array.
135 |
136 | ```python
137 | def test_str(self):
138 | assertEqual(self.sln.ArrayPairSum(["herp", "derp"]), 0)
139 | ```
140 |
141 | * run `./runTests.py` locally to show that this test (most likely) fails.
142 | * commit and push your new changes to GitHub, noting that this commit "Adds failing tests for returning 0 on string array".
143 | * ensure Jenkins picks up the changes, and that this tests fails when Jenkins tests it
144 | * now fix the code to pass this test. run `./runTests.py` locally to check
145 | * when you're ready, commit and push your fix to GitHub, then check Jenkins to ensure your build succeeds and that all tests pass
146 |
147 |
--------------------------------------------------------------------------------