From 0c4a4216a4eacaa9e009ec33d913b61aa267de33 Mon Sep 17 00:00:00 2001
From: Manuel Reis <reis@dkrz.de>
Date: Mon, 31 Mar 2025 18:19:12 +0200
Subject: [PATCH] Complete examples and handson

---
 lectures/tooling-ci/slides.qmd | 376 ++++++++++++++++++++++++++-------
 1 file changed, 296 insertions(+), 80 deletions(-)

diff --git a/lectures/tooling-ci/slides.qmd b/lectures/tooling-ci/slides.qmd
index e334be6..f2b354f 100644
--- a/lectures/tooling-ci/slides.qmd
+++ b/lectures/tooling-ci/slides.qmd
@@ -1,83 +1,232 @@
 ---
 title: "Tooling and Continuous Integration"
 subtitle: ""
-author: "Lukas Kluft, Tobias Kölling, (Flo)"
+author: ""
 ---
 
 # *Software Development* Tooling
 
-## Software to create software 😵
-* Validate code
-* Test functionality
+::: {.incremental}
+
+- Software to develop software 😵
+
+:::
+
+## Tools aim at:
+* Simplifying
+	- Abstractions
+	- Encapsulation
+* Validate & Test
+* Deploy / install
 * Speedup development
-* Make things easier
+
+:::{.notes}
+[Extended definition](https://en.wikipedia.org/wiki/Programming_tool)
+:::
+
+## _Toolchain_ example
+
+
+```{mermaid}
+flowchart LR
+  classDef tool stroke:#f96,shape:stadium-shaped
+  A[Source Code]
+  E([Editor]):::tool
+  C([Compiler]):::tool
+  I([Interpreter]):::tool
+  OS([Op. System]):::tool
+  B[Executable File]
+  O[["Output"]]
+  A --> E --> A
+  A --> C --> B
+  A --> I --> O
+  B --> OS --> O
+```
+
+```{mermaid}
+flowchart LR
+ subgraph Legend
+  f[File]
+  t([Tool])
+  style t stroke:#f96
+  o[[Result]]
+ end
+```
+. . .
+
+:::{.smaller}
+In python, compilation and execution are done in the same process.
+:::
+
+## Example
+
+```
+$ vim example.c
+```
+```C
+#include <stdio.h>
+int main() {
+    printf("Hello world\n");
+    return 0;
+}
+```
+```
+$ gcc example.c
+$ ./a.out
+Hello world!
+```
+
+. . .
+
+Modify the souce `file`, `compile` and `execute`:
+
+. . .
+
+```
+$ sed -i 's/world/there/g' example.c
+$ gcc example.c 
+$ ./a.out
+Hello there!
+```
+
+. . . 
+
+We use two programs/**tools** ( `sed` and `gcc`) to achieve this.
+
+
+## The devious way...
+
+Change output of executable from `Hello world!` to `Hello there!` **without** (re)compiling!
+
+:::{.smaller}
+Directly maniputale the binary executable. Refer to the [ASCII table](https://en.wikipedia.org/wiki/ASCII#Character_set)
+:::
+
+. . .
+```
+$ sed -i 's/\x77\x6f\x72\x6c\x64/\x74\x68\x65\x72\x65/g' a.out
+$ ./a.out 
+Hello there!
+```
+
+. . .
+
+This is to show how important compilers and interpreters are!
+
+. . .
+
+For this example it did not need to be so cumbersome:
+```
+$ sed -i 's/there/world/g' a.out
+$ ./a.out
+Hello world!
+```
+
+. . .
+
+:::{.smaller}
+For completion (`hexdump` or `xxd` can help decoding binary contents)
+```
+$ xxd a.out | grep 'Hello world!'
+00002000: 0100 0200 4865 6c6c 6f20 776f 726c 6421  ....Hello world!
+$ python3 -c 'print(b"Hello world!".hex(" ",2))'
+4865 6c6c 6f20 776f 726c 6421
+```
+:::
 
 ## Making things easier 
 :::: {.columns}
 
 ::: {.column width="50%"}
+::: {.smaller}
 Python
 ```python
 def say_hi():
     print("Hello World")
 
-
 ```
- 
- 
-:::{.justify}
-Python **interpreter** is implemented in C, which is **compiled** into Machine Code.
+Disassembled bytecode
+
+```python
+import dis
+dis.dis(say_hi)
+  2    0 LOAD_GLOBAL       0 (print)
+       2 LOAD_CONST        1 ('Hello World')
+       4 CALL_FUNCTION     1
+       6 POP_TOP
+       8 LOAD_CONST        0 (None)
+      10 RETURN_VALUE
 
-This abstraction makes the process of developing a program, **easier** and **faster**.
+```
 :::
 :::
+
 ::: {.column width="50%"}
-Assembly
-```asm
-  0           RESUME                   0
 
-  1           LOAD_CONST               0 (<code object say_hi at 0x5f19d84931b0, file "example.py", line 1>)
-              MAKE_FUNCTION
-              STORE_NAME               0 (say_hi)
-              RETURN_CONST             1 (None)
+The python _interpreter_ **generates** and **executes** bytecode from the source files
 
-Disassembly of <code object say_hi at 0x5f19d84931b0, file "example.py", line 1>:
-  1           RESUME                   0
+::: {.incremental}
+- The **interpreter** is written in C and **compiled** into Machine Code.
+:::
 
-  2           LOAD_GLOBAL              1 (print + NULL)
-              LOAD_CONST               1 ('Hello world')
-              CALL                     1
-              POP_TOP
-              RETURN_CONST             0 (None)
-```
 :::
 :::
 
+. . .
+
+::: {.smaller}
+This abstraction makes it **easier** and **faster**  to develop a program.
+:::
+
+# Categories 
+
+Lets check on types of tools
+
+
 
 ## Are programming languages tools?🤷
 
+. . .
+
+Yes & No!
+
+::: {.notes}
+Languages are an abstract concept but they play the fundamental role of programming.
+:::
+
+:::{.incremental}
 * Compiler/Interpreter is a tool
-	- `/usr/bin/python3` follows the [Python Language Reference](https://docs.python.org/3/reference/index.html)
+	- [`CPython`](https://www.python.org/), [`PyPy`](https://pypy.org/) and [`Pythran`](https://pythran.readthedocs.io/en/latest/) follow the [Python Language Reference](https://docs.python.org/3/reference/index.html)
 * Libraries / modules (often) come with tools
 	- `pdb` - python debugger
 	- `pip` - famous package installer
+:::
+
+
+## What about the Operating System? 
+
+It's a software that manages running programs. So ... **yes!**
+
+. . . 
 
-## What about the Operating System?
+Generally the execution of a program can only happen by interacting with the operating system.
 
-It's a software that manages running programs. So yes!
+. . .
 
-It often supplies users with software development tools:
+:::{.smaller}
+There are bundles of development tools for each operating system:
 
-* [🪟](https://developer.microsoft.com/en-us/windows/dev-tools/) `dev-tools`
-* [🍎](https://developer.apple.com/xcode/) `xcode`
-* [🐧](https://itsfoss.com/build-essential-ubuntu/) `build-essential`
+- [🪟](https://developer.microsoft.com/en-us/windows/dev-tools/) `dev-tools`
+- [🍎](https://developer.apple.com/xcode/) `xcode`
+- [🐧](https://itsfoss.com/build-essential-ubuntu/) `build-essential`
+:::
 
 
 ## Tools in the development environment
  
 - Package managers (`conda`, `pyenv`, `uv`)
 - Version control systems (`git`)
-- Editors, IDEs - Integrate Development Environments
+- Editors, IDEs - Integrated Development Environments
 - Linters, formatters, type-checkers (`flake8`, `black`, `ruff`)
 - Compilers and/or Interpreters (e.g. `gcc`, `python`)
 - Testing tools (`pytest`,[`unittest`](https://docs.python.org/3/library/unittest.html))
@@ -95,7 +244,8 @@ It often supplies users with software development tools:
 
 * All languages follow a syntax.
 * Easy for us to make mistakes/typos
-* Hard to understand where the problem is
+* Spot where the problem are.
+
 
 ::: {.columns}
 
@@ -106,7 +256,7 @@ def helloworld():
      print('world')
 
 helloworld()
- ```
+```
 :::
 
 :::{.column}
@@ -118,13 +268,11 @@ $ python3 helloworld.py
 IndentationError: unindent does not match any outer indentation level
 ```
 :::
-
 :::
 
 ## Linters & formatters
 
 ::: {.columns}
-
 ::: {.column}
 Popular linters
 ```
@@ -138,7 +286,6 @@ helloworld.py:3:4: E0001: Parsing failed: 'unexpected indent (helloworld, line 3
 ```
 
 :::
-
 ::: {.column}
 Formatters
 ```
@@ -156,9 +303,7 @@ def helloworld():
 
 helloworld()
 ```
-
 :::
-
 :::
 
 ```
@@ -170,27 +315,98 @@ Found 2 errors.
 
 ## Hands-on Session {.handson}
 
-`git precommit hook` exercise?
-- It could be linting .gitlab.yaml
-- 
-- Apply provided faulty patch, check if pushing code  
+Simple `git precommit hook` exercise.
+
+- Clone this repo: [ci-example](https://gitlab.dkrz.de/generic-software-skills/ci-example)
+- Use a linter to check if the file `.gitlab.yml` is complying to the Gitlab [YAML](https://docs.gitlab.com/ci/yaml/) syntax refence
+
+. . .
+
+:::{.smaller}
+```bash
+module load git python3
+python3 -m pip install yamllint
+[[ ! $PATH =~ "${USER}/.local/bin" ]] && PATH=${PATH}:/home/$(echo $USER | cut -c1)/$USER/.local/
+git clone https://gitlab.dkrz.de/generic-software-skills/ci-example
+cd ci-example
+yamllint .gitlab.yml
+```
+:::
+
+:::aside
+Does it succeed or fail?
+:::
+
+## Pre-commit hook 🪝 {.handson}
+
+:::{.smaller .incremental}
+- Create a shell script named `.git/hooks/pre-commit` so that:
+	- The yaml linter is called on the `yml` file
+	- Returns the exit code of the linter (0 if sucess else error) 
+- Fix the yaml file to fix warnings and erros:
+	- Add (stage) and commit the changes to automatically trigger the linter.
+:::
+
+. . .
+
+:::{.smaller}
+- Bonus: do that only when `.gitlab-ci.yml` is stagged (you can use `git diff --cached --name-only` to check that)
+:::
+
+::: aside
+Useful git _Fu_:
+
+- `git commit -am 'Fix yml syntax' # Adds and commits modification`
+- `git reset HEAD~1 # Undo last commit!`
 
+:::
+::: notes
+```
+$ git add .gitlab-ci.yml 
+$ git diff --cached --name-only
+.gitlab-ci.yml
+$ git restore --staged .gitlab-ci.yml 
+$ git diff --cached --name-only`
+```
+:::
+
+
+## Solution {.handson visibility="hidden"}
+
+Content of `.git/hooks/pre-commit`
+
+```bash
+#!/bin/sh
+code=0
+if git diff --cached --name-only | grep -q '.gitlab-ci.yml'; then 
+    echo Running linter on .gitlab-ci.yaml
+    yamllint .gitlab-ci.yml
+    code=$?
+    echo Result: $code
+fi
+exit $code
+```
+
+# Continuous Integration (CI) {.smaller}
 
-[//]:... The idea is that when introducing a change to a code-base, it should be checked **automatically**. 
-# Continuous Integration (CI)
- * Automated builds and tests with each code change
- * Rapid feedback on build and test status
- * Consistent, reproducible testing environment
- * Frequent merging to reduce integration conflicts
- * Improved collaboration across development teams
+* Automated builds and tests with each code change
+* Rapid feedback on build and test status
+* Consistent, reproducible testing environment
+* Frequent merging to reduce integration conflicts
+* Improved collaboration across development teams
+
+::: notes
+... The idea is that when introducing a change to a code-base, it should be checked **automatically**. 
+:::
 
 ## Where?
 
 * Git repositoris are the **perfect place for CI**!
-* The CI assesses if a commit is up to the expectations ("Passes/Fails the CI").
+* The CI assesses if a commit is up to the expectations
+	- "Passes/Fails the CI"
 * Provided on popular git hosting systems
-	- [GitLab CI](https://docs.gitlab.com/ee/ci/)
-	- [GitHub Actions](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions).
+	- [GitLab CI](https://docs.gitlab.com/ee/ci/) as pipelines
+	- [GitHub Actions](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions). 
 
 
 ## What to expect?
@@ -209,15 +425,8 @@ Found 2 errors.
 	- One can have many variants of the same stage
 * Tests to be done in each of them (to be continued...)
 
-#
-[//]::(https://gitlab.dkrz.de/generic-software-skills/lecture-materials/-/pipelines/96666)
-[//]::(https://github.com/faster-cpython/cpython/actions/runs/13454935981)
-
-## Example
-
-:::: {.columns}
+## Example of `.gitlab-ci.yml` {.smaller}
 
-::: {.column width="50%"}
 ```yml
 stages:
  - lint
@@ -226,29 +435,36 @@ stages:
 
 linter:
   stage: lint
-  image: python # container with basic python tools
+  image: python # container image with basic python tools
   script:
     - pip install flake8
     - flake8 . --count --exit-zero --statistics
-```
-:::
-::: {.column width="50%"}
-```yml
+
 type-check:
-	stage: build
-	image: python
-	script:
-		- pip install mypy
-		- mypy .
+  stage: build
+  image: python
+  script:
+    - pip install mypy
+    - mypy .
 ```
-:::
-::::
+
+## Real case examples
+
+- [GitHub Actions]( https://github.com/faster-cpython/cpython/actions/runs/13454935981) workflow for CPython
+- Course lectures on [Gitlab CI](https://gitlab.dkrz.de/generic-software-skills/lecture-materials/-/pipelines/96666)
+	- Gitlab CI syntax: [docs.gitlab.com/ci/yaml](https://docs.gitlab.com/ci/yaml/)
+
 
 ## Hands-on Session {.handson}
 
-* Create a gitlab CI pipeline for [repo](https://gitlab.dkrz.de/generic-software-skills/ci-example) that:
-1. Install tools to lints your changes
-2. Makes sure environment has required dedependecies 
-3. Runs the program (no testing yet)
-4. Bonus: creates an executable?
+Change the Gitlab CI pipeline for [repo](https://gitlab.dkrz.de/generic-software-skills/ci-example) so that:
+
+- Install tools to lint your source code
+- Runs the program and check if the output is "Hello world!"
+- Bonus: Setup [ruff-pre-commit](https://docs.astral.sh/ruff/integrations/#pre-commit) and [Gitlab CI](https://docs.astral.sh/ruff/integrations/#gitlab-cicd)
 
+. . .
+
+```
+pip install pre-commit
+```
-- 
GitLab