Skip to content
This repository was archived by the owner on Jul 2, 2021. It is now read-only.

Commit 1f410d7

Browse files
committed
Example Getting Started - More README and small pipeline changes.
1 parent 10aab42 commit 1f410d7

File tree

4 files changed

+189
-11
lines changed

4 files changed

+189
-11
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Basically you can run lead like this:
126126
lead [<job> ...] [--<parameter>=<value> ...]
127127
```
128128

129-
Where `<job>` is one (ore more) of the jobs of your pipeline script. And `<parameter>` and the according `<value>` are parameters your jobs will receive on execution[*](#Notes).
129+
Where `<job>` is one (ore more) of the jobs of your pipeline script. And `<parameter>` and the according `<value>` are parameters your jobs will receive on execution.
130130

131131
Make sure you are executing it from a directory containing a `pipeline.py` file.
132132

examples/getting_started/README.md

+177
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,179 @@
11
# Lead - Getting Started
22

3+
This example shows the basics and possibilities of Lead. It does not include a real project, just a simple pipeline.py file.
4+
5+
## Hello World
6+
7+
First of all the obvious example. Just printing "Hello World" to the logs.
8+
9+
Start by changing to the directory of this example. Execute the following line:
10+
11+
```bash
12+
lead hello_world
13+
```
14+
15+
This should print something like the following log:
16+
17+
```bash
18+
==============================
19+
20+
INFO | Running hello_world
21+
22+
==============================
23+
24+
25+
*** CONTAINER OUTPUT
26+
27+
Hello World! :)
28+
29+
*** END OF OUTPUT
30+
31+
==============================
32+
33+
Pipeline ended succesfully. :)
34+
35+
==============================
36+
```
37+
38+
And this is what happened:
39+
40+
Take a look inside the `pipeline.py` file. The first job you will find has the function name `hello_world`. This is the function that has been executed. Defining a job in lead is as simple as creating a function in Python. You will get a variable called `exec`. This is a helper you can use to define what should happen inside the container. You also get something called `*args` and `**kwargs`. These are some kind of placeholders in Python for more parameters a function can receive but which are not explicitly mentioned in the parameter list. You can ignore them for now.
41+
42+
The magic happens in the two lines before the definition of the function. The decorator `@job` tells Lead that this function is actually a job you can execute from the command line. This is also the place you can enter more meta information about this job. Then there is the `@docker` decorator. We are using this decorator to tell Lead more about the container we want to use inside our job. For now the only thing to define is the image name - `alpine` - for this job.
43+
44+
So Lead will check if there is already an image called `alpine` on your machine. If not it will download the image. After that it will start a container of this image and give the helper function `exec` to your function to execute something inside the container. It will do even more for you automatically in the background, like mounting the current working directory inside the container, removing the container after execution of your job and so on.
45+
46+
You can use `exec` by first providing the script to execute inside your container and optionally a shell this should be executed in. In Python we can use a string starting with triple `"` which enables us to write the script in several lines and to use `"` inside it without having to escape them. Try changing the script and run the command again. You can also enter a `ls` to see the files of the current directory (probably `README.md` and `pipeline.py`) in the log.
47+
48+
## Container Output And Return Codes
49+
50+
This is example will show you how to get access to and use the output of the container and the return code.
51+
52+
The `exec` function will return two values: `exit_code` and `output`. The `exit_code` is the real exit code of the execution inside the container. `output` will contain the complete output of your script in one string.
53+
54+
Execute the following command.
55+
56+
```bash
57+
lead output_and_return
58+
```
59+
60+
You will get something like the following output.
61+
62+
```bash
63+
==============================
64+
65+
INFO | Running output_and_return
66+
67+
==============================
68+
69+
70+
*** CONTAINER OUTPUT
71+
72+
I am successfully running inside an ubuntu container
73+
Now this script exits with return code 9, but the build should not fail because of the output condition
74+
75+
*** END OF OUTPUT
76+
Exit code is: 9
77+
Command output is:
78+
I am successfully running inside an ubuntu container
79+
Now this script exits with return code 9, but the build should not fail because of the output condition
80+
81+
82+
==============================
83+
84+
Pipeline ended succesfully. :)
85+
86+
==============================
87+
```
88+
89+
We see the exit code was 9. This was intended and caused by `exit 9` inside the script. But why did Lead tell us that the `Pipeline ended successfully. :)`? Because there is a second condition inside the job which checks if there was a specific keyword in the output. In this case `successfully`. This is true, because we echoed this word inside our script.
90+
91+
Enable the commented lines and disable the first execution of `exec`. Run the command `lead output_and_return` again. Now the pipeline fails because there is no keyword `successfully` anymore. Lead will also fail with the exit code of the job. You can verify this by running `echo $?` in your command line.
92+
93+
## Manipulating Files
94+
95+
As previously mentioned the current working directory is mounted as a volume inside the container. You have full access to the files. It is possible to read, write, copy, move, remove, and so on. This enables us to run something like Maven, Grunt, etc. But for this example we will just create a new file called `example.txt` inside our current directory.
96+
97+
Run
98+
99+
```bash
100+
lead alter_file
101+
```
102+
103+
You will see nothing special in the output. That's because we echoed everything inside the `example.txt`. Look in the current directory and you will find this exact file. It should container the current date, a new line of text and a third line with `Today SUSI wants to EAT A HAMBURGER.` If you look inside the job you will see that the corresponding line looks like this:
104+
105+
```bash
106+
echo "Today {subj} wants to {verb} {obj}." >> example.txt;
107+
```
108+
109+
Python replaces the placeholders because of the `format(**locals())` function we appended to the script string. The function `locals()` does contain all local variables of the current context in Python. So in this case the three previously defined variables `subj`, `verb` and `obj`. The `**` are just Pythons way of spreading these, so `format()` can use them. The equivalent but longer version would be to set them explicitly like this: `format(subj=subj, verb=verb, obj=obj)`.
110+
111+
By the way, for these three variables a function is used which you will find at the end of the `pipeline.py` file. This is not a job function but can be used as a helper function for typical or repeating tasks. These normal kind of functions will help you organize your pipeline and keep it readable.
112+
113+
## More Logic And Command Line Parameter
114+
115+
In the last example there is a more complex script containing a conditional statement. Execute the following command.
116+
117+
```bash
118+
lead helloAgain
119+
```
120+
121+
You will see something like the following output:
122+
123+
```bash
124+
==============================
125+
126+
INFO | Running helloAgain
127+
128+
==============================
129+
130+
131+
*** CONTAINER OUTPUT
132+
133+
Hello World!
134+
135+
*** END OF OUTPUT
136+
137+
==============================
138+
139+
Pipeline ended successfully. :)
140+
141+
==============================
142+
```
143+
144+
You may wonder why you had to execute `lead helloAgain` and not something like `lead complex_logic`. This is because of the `@job` decorator and more specifically of the `name` given there. Lead prefers a job name given there and use the real function name as a fallback.
145+
146+
Execute the command again but add a parameter called `name`:
147+
148+
```bash
149+
lead helloAgain --name=Jason
150+
```
151+
152+
This time the output should look like this:
153+
154+
```bash
155+
==============================
156+
157+
INFO | Running helloAgain
158+
159+
==============================
160+
161+
162+
*** CONTAINER OUTPUT
163+
164+
Not hello world but hello JASON.
165+
166+
*** END OF OUTPUT
167+
168+
==============================
169+
170+
Pipeline ended successfully. :)
171+
172+
==============================
173+
```
174+
175+
You see that the output has changed. It does contain the name entered on the command line.
176+
177+
If you look closely to the function header you will see a new parameter called `name`. This is the parameter we added to the command line. The value `World` is just a default value if no parameter is given.
178+
179+
But the different output also shows us that you can use even use complex logic inside your container script. So basically there is no limitation of what you can do.

examples/getting_started/pipeline.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def hello_world(exec, *args, **kwargs):
1010

1111

1212

13+
1314
# This example shows how to use the return code of a container
1415
# and the output to do some post execution checks.
1516
@job(description="Example of working with return code and log output.")
@@ -50,7 +51,7 @@ def output_and_return(exec, *args, **kwargs):
5051
# inside the container. So you have full access to it.
5152
@job(description="Example of manipulating files inside the current working directory.")
5253
@docker("ubuntu:16.04")
53-
def alterFile(exec, *args, **kwargs):
54+
def alter_file(exec, *args, **kwargs):
5455

5556
subj=nameToUpper("Susi") # See below for nameToUpper function
5657
verb=nameToUpper("eat")
@@ -61,9 +62,9 @@ def alterFile(exec, *args, **kwargs):
6162
# For a more specific way see the function complexLogic
6263
exec("""
6364
64-
date +%d.%m.%Y > example.txt;
65-
echo "This file has been created inside the container" >> example.txt;
66-
echo "Today {subj} wants to {verb} {obj}." >> example.txt;
65+
date +%d.%m.%Y > example.txt
66+
echo "This file has been created inside the container" >> example.txt
67+
echo "Today {subj} wants to {verb} {obj}." >> example.txt
6768
6869
""".format(**locals()), shell="bash")
6970

@@ -74,20 +75,20 @@ def alterFile(exec, *args, **kwargs):
7475
# Lead will prefer the name given in @job and fallback to the function name of
7576
# none is specified in @job.
7677
# Try changing "World" to something different and execute this job again to see this script really working
77-
# You can also use command options. Try executing "lead helloStranger --name=Peter".
78-
@job(name="helloStranger", description="Echoing hello to somebody.")
78+
# You can also use command parameters. Try executing "lead helloAgain --name=Peter".
79+
@job(name="helloAgain", description="Echoing hello to somebody.")
7980
@docker("alpine")
80-
def complexLogic(exec, name="World", *args, **kwargs):
81+
def complex_logic(exec, name="World", *args, **kwargs):
8182

8283
name=nameToUpper(name) # See below for nameToUpper function
83-
84+
8485
exec("""
8586
8687
if [ "{name}" = "WORLD" ]
8788
then
8889
echo "Hello World!"
8990
else
90-
echo "Not hello world but hello {name}"
91+
echo "Not hello world but hello {name}."
9192
fi
9293
9394
""".format(name=name), shell="sh")

lead.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,6 @@ def pre_check(jobs_arg, job_dict):
316316
print()
317317
print("==============================")
318318
print()
319-
print("Pipeline ended succesfully. :)")
319+
print("Pipeline ended successfully. :)")
320320
print()
321321
print("==============================")

0 commit comments

Comments
 (0)