<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Devops on Dag's home</title><link>https://dag7.it/tags/devops/</link><description>Recent content in Devops on Dag's home</description><generator>Hugo</generator><language>en</language><managingEditor>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</managingEditor><webMaster>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</webMaster><lastBuildDate>Tue, 12 May 2026 16:45:00 +0200</lastBuildDate><atom:link href="https://dag7.it/tags/devops/index.xml" rel="self" type="application/rss+xml"/><item><title>How to move from GitHub to Codeberg</title><link>https://dag7.it/posts/guide-how-to-move-from-github-to-codeberg/</link><pubDate>Tue, 12 May 2026 16:45:00 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/guide-how-to-move-from-github-to-codeberg/</guid><description>&lt;h1 id="migrate-from-github-to-codeberg"&gt;Migrate from Github to Codeberg&lt;/h1&gt;
&lt;p&gt;Are you tired of GitHub social tab? What about issues tab being &amp;ldquo;removed&amp;rdquo; in favor of AI?&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s AI everywhere nowadays, but Github was one of the places that were left untouched.&lt;/p&gt;
&lt;p&gt;Not anymore.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!INFO] FYI
Some code has been written and tested with the help of an AI&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why"&gt;Why&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Codeberg is not controlled by a commercial entity, but by its non-profit association based in Berlin, Germany
&lt;ul&gt;
&lt;li&gt;this means that every change is led by the community&lt;/li&gt;
&lt;li&gt;no forced AI&lt;/li&gt;
&lt;li&gt;no stupid UI/UX changes &amp;ldquo;because they say so&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Codeberg servers are based in Berlin, in EU, unlike Github servers&lt;/li&gt;
&lt;li&gt;Codeberg run Forgejo that is open source&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t want to use a popular platform, whatever the reason&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how"&gt;How&lt;/h2&gt;
&lt;p&gt;The general idea is: use Codeberg as main and GIthub as a mirror. Or viceversa.&lt;/p&gt;
&lt;p&gt;Migrating from GitHub to Codeberg is not a straightforward process.&lt;/p&gt;
&lt;p&gt;The estimated time for the entire procedure is about 45min.&lt;/p&gt;
&lt;h2 id="preliminary-steps"&gt;Preliminary steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create a Github Token with &amp;ldquo;all&amp;rdquo; permissions (see &lt;a href="https://github.com/settings/tokens"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Create a Codeberg with &amp;ldquo;all&amp;rdquo; permissions (see &lt;a href="https://codeberg.org/user/settings/applications"&gt;here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Save them somewhere in your computer. You&amp;rsquo;ll need both of them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s export these variables for the current shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CODEBERG_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;codeberg-username&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;CODEBERG_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;codeberg-token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gh-token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;GITHUB_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;github-username&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;ll need them later. Make sure by giving &lt;code&gt;echo $CODEBERG_TOKEN&lt;/code&gt; it prints &lt;code&gt;&amp;lt;codeberg-token&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE] Security Issues
It&amp;rsquo;s not a safe idea issuing these commands, due to the &lt;code&gt;history&lt;/code&gt; shell command. If you are an advanced user, and feel that &amp;rsquo;this is bad&amp;rsquo;, find a proper safer way. One idea is to save it in .bashrc and reload the bash, and remove everything when it&amp;rsquo;s over.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="github-spring-cleaning-regardless-of-the-season"&gt;Github: spring cleaning regardless of the season&lt;/h2&gt;
&lt;p&gt;In your public repos: is there any fork that you don&amp;rsquo;t use? If yes, delete it.&lt;/p&gt;
&lt;p&gt;In your private ones: is there any project that you started years ago and never touched anymore because you were too scary or full of work? It is a good time to delete them.&lt;/p&gt;
&lt;p&gt;Is your public repo a private one? Make sure to &amp;ldquo;publish&amp;rdquo; it and viceversa.&lt;/p&gt;
&lt;p&gt;Unless you&amp;rsquo;re ready to deal with Forgejo and so on, the repos that has workflows or something more complicated, should remains on Github.&lt;/p&gt;
&lt;h2 id="optional-download-all-your-github-repos-in-local"&gt;(optional) Download all your Github repos in local&lt;/h2&gt;
&lt;p&gt;You never know.&lt;/p&gt;
&lt;p&gt;Save this script in your home and launch it with &lt;code&gt;./github_to_local.sh&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/usr/bin/env bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -euo pipefail
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;DEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/github-backup&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DEST&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$DEST&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; :&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;repos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Accept: application/vnd.github+json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://api.github.com/user/repos?per_page=100&amp;amp;page=&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;type=owner&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -o &lt;span class="s1"&gt;&amp;#39;&amp;#34;clone_url&amp;#34;: *&amp;#34;[^&amp;#34;]*&amp;#34;&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; cut -d &lt;span class="s1"&gt;&amp;#39;&amp;#34;&amp;#39;&lt;/span&gt; -f4&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -z &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$repos&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; repo in &lt;span class="nv"&gt;$repos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;basename &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; .git&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$repo_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Skipping existing repo: &lt;/span&gt;&lt;span class="nv"&gt;$repo_name&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Cloning &lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; git clone &lt;span class="s2"&gt;&amp;#34;https://&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;#https://&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;page &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="move-from-github-to-codeberg"&gt;Move from Github to Codeberg&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/LionyxML/migrate-github-to-codeberg/blob/main/migrate_github_to_codeberg.sh"&gt;This excellent script&lt;/a&gt; from LionyxML is pretty customizable and allow us to move from one place to another the repos.&lt;/p&gt;
&lt;p&gt;Make sure to either export the variables as explained at the beginning of the guide, or fill the variables at the beginning with your data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget https://raw.githubusercontent.com/LionyxML/migrate-github-to-codeberg/refs/heads/main/migrate_github_to_codeberg.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Everything is written in the file, but here&amp;rsquo;s a small portion, that&amp;rsquo;s how I set up:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# !!!!! &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Since you have exported your usernames and tokens before, there is no need to redeclare them here. If needed, uncomment them.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# !!!!!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# GitHub username and personal access token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# GITHUB_USERNAME=&amp;#34;YourGitHubUsername&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# GITHUB_TOKEN=&amp;#34;YourGitHubToken&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Codeberg username and personal access token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CODEBERG_USERNAME=&amp;#34;YourCodebergUsername&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CODEBERG_TOKEN=&amp;#34;YourCodebergToken&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# REPOSITORIES array with repository names you want to migrate, one per row with commas&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# blank = ALL repositories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;REPOSITORIES&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# OWNERS array with specific usernames whose repositories you want to migrate, one per row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# blank = ALL repositories&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;OWNERS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_USERNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since we want to migrate everything&amp;hellip; let&amp;rsquo;s leave everything as it is, but I&amp;rsquo;m not interested in the code I&amp;rsquo;ve created in the organizations.&lt;/p&gt;
&lt;p&gt;Therefore, I&amp;rsquo;ll write my name in &amp;ldquo;owners&amp;rdquo; array.&lt;/p&gt;
&lt;p&gt;Save the script in your home directory, fill with your information, make it executable and launch it.&lt;/p&gt;
&lt;p&gt;Wait a while and&amp;hellip; boom, your Codeberg account is now populated.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!Danger] Warning
Make sure to change visibility to &amp;ldquo;private&amp;rdquo; those repos that you will manage through Github, or even better, delete them. This will help Codeberg in being a free, cleaner space for everybody. Furthermore, you&amp;rsquo;ll avoid code duplication.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Make also sure to adhere to
&lt;a href="https://docs.codeberg.org/getting-started/what-is-codeberg/"&gt;their principles&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="following-and-followers"&gt;Following and followers&lt;/h2&gt;
&lt;p&gt;We need to perform two actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check if a user exists&lt;/li&gt;
&lt;li&gt;Fetch the list of following and followers Github users in our profile, and try to see if there&amp;rsquo;s a match on Codeberg&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="check-if-a-user-exists"&gt;Check if a user exists&lt;/h3&gt;
&lt;p&gt;In a file named &lt;code&gt;check_codeberg.sh&lt;/code&gt; let&amp;rsquo;s write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/usr/bin/env bash 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; user in &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -o /dev/null -w &lt;span class="s2"&gt;&amp;#34;%{http_code}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;       &lt;span class="s2"&gt;&amp;#34;https://codeberg.org/api/v1/users/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;200&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;       &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; exists&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;span class="k"&gt;else&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;       &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; does not exist&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;span class="k"&gt;fi&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make it executable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x check_codeberg.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And run it with an username:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./check_codeberg.sh torvalds
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;torvalds exists
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="fetch-the-list-of-following-and-followers-github-users"&gt;Fetch the list of following and followers Github users&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s move to the second action.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s retrieve following people of our own profile with these piece of code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://api.github.com/users/&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_USERNAME&lt;/span&gt;&lt;span class="s2"&gt;/following?per_page=100&amp;amp;page=&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;jq &lt;span class="s1"&gt;&amp;#39;length&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;break&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -r &lt;span class="s1"&gt;&amp;#39;.[].login&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; following.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;((&lt;/span&gt;page++&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And followers:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -s -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://api.github.com/users/&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_USERNAME&lt;/span&gt;&lt;span class="s2"&gt;/followers?per_page=100&amp;amp;page=&lt;/span&gt;&lt;span class="nv"&gt;$page&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;jq &lt;span class="s1"&gt;&amp;#39;length&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt; -eq &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;break&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;jq -r &lt;span class="s1"&gt;&amp;#39;.[].login&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; followers.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;((&lt;/span&gt;page++&lt;span class="o"&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We cannot merge both instructions because we may have more followers than following and viceversa.&lt;/p&gt;
&lt;h3 id="all-together-now"&gt;All together now&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s now time to see who&amp;rsquo;s on codeberg.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s merge following and followers list into one file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat following.txt followers.txt &lt;span class="p"&gt;|&lt;/span&gt; sort &lt;span class="p"&gt;|&lt;/span&gt; uniq &amp;gt;&amp;gt; people.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now, let&amp;rsquo;s find out who&amp;rsquo;s online:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; -r user&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   curl -s -o /dev/null -w &lt;span class="s2"&gt;&amp;#34;%{http_code}&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;   &lt;span class="s2"&gt;&amp;#34;https://codeberg.org/api/v1/users/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -q &lt;span class="m"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt; found! -&amp;gt; https://codeberg.org/&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; people.txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;[!NOTE] Enhancements
This could be further enhanced by calling Codeberg API Keys and blindly following every account. Since sometimes people&amp;rsquo;s username may be different than the github ones (like me), always check profiles before blindly following everyone&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="thats-all-folks"&gt;That&amp;rsquo;s all folks!&lt;/h2&gt;
&lt;p&gt;Have I been useful? Support my work [on ko-fi](&lt;a href="https://ko-fi.com/dag7_"&gt;ko-fi.com/dag7&lt;/a&gt;, even a small euro could make the difference.&lt;/p&gt;
&lt;p&gt;Thanks for reading this.&lt;/p&gt;</description></item><item><title>GitLab Pipeline Tiramisu</title><link>https://dag7.it/posts/gitlab-pipeline-tiramisu/</link><pubDate>Mon, 08 Sep 2025 15:29:03 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/gitlab-pipeline-tiramisu/</guid><description>&lt;h2 id="gitlab-cicd-pipeline-tutorial-for-beginners"&gt;GitLab CI/CD Pipeline Tutorial for Beginners&lt;/h2&gt;
&lt;p&gt;During a DevOps crash course, I&amp;rsquo;ve been called to teach how to setup a simple GitLab pipeline.&lt;/p&gt;
&lt;p&gt;It wasn&amp;rsquo;t easy: the people who took part in that course, were from very different backgrounds: backend in PHP, frontend, people out of school at their first job employment&amp;hellip; despite of this, I&amp;rsquo;ve talked to them about what a devops does, who is it, and how pipelines are important.&lt;/p&gt;
&lt;p&gt;In this article, you are going to learn how to setup a simple toy pipeline, in order to experiment a little bit with GitLab runners.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t care just gimme the recipe and I&amp;rsquo;ll figure out everything else!!!
&lt;a href="#i-got-it-now-i-want-to-write-a-toy-pipeline-that-describes-a-tiramisu-recipe"&gt;here it is&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="how-to-do-it"&gt;How to do it&lt;/h2&gt;
&lt;p&gt;The first step is to have a GitLab account. You can sign up for a GitLab account &lt;a href="https://gitlab.com"&gt;here&lt;/a&gt;. I personally don&amp;rsquo;t use that much GitLab, but I will move provided my use cases fits GitLab.&lt;/p&gt;
&lt;p&gt;Next, you should create a repository:
&lt;img src="https://dag7.it/img/gitlab-pipeline-1.png" alt="gitlab-pipeline-1.png"&gt;&lt;/p&gt;
&lt;p&gt;fill the blanks as you prefer&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-2.png" alt="gitlab-pipeline-2.png"&gt;&lt;/p&gt;
&lt;p&gt;and click the blue button &amp;ldquo;create a project&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-3.png" alt="gitlab-pipeline-3.png"&gt;&lt;/p&gt;
&lt;h2 id="runner-yaml-pipeline-what-are-you-talking-about"&gt;Runner, YAML, pipeline&amp;hellip; what are you talking about?&lt;/h2&gt;
&lt;p&gt;Now it&amp;rsquo;s time to write a small pipeline and set the runner.&lt;/p&gt;
&lt;h3 id="pipeline"&gt;Pipeline&lt;/h3&gt;
&lt;p&gt;A &lt;strong&gt;pipeline&lt;/strong&gt; is a group of steps (named &amp;ldquo;&lt;strong&gt;stages&lt;/strong&gt;&amp;rdquo;) that include &lt;strong&gt;jobs&lt;/strong&gt;, what we need to do in each stage.&lt;/p&gt;
&lt;p&gt;To understand more this concept, imagine cooking a Tiramisu: you have to first &lt;em&gt;prepare ingredients&lt;/em&gt;, then you have to &lt;em&gt;assemble&lt;/em&gt; them, there is a &lt;em&gt;cooling&lt;/em&gt; part and the final step is &lt;em&gt;service&lt;/em&gt;. These all stages.&lt;/p&gt;
&lt;p&gt;Jobs can be, in the stage of &lt;em&gt;preparing ingredients&lt;/em&gt;: make some coffee, whip cream and sugar&amp;hellip;&lt;/p&gt;
&lt;p&gt;Stages and jobs together in a file, form a pipeline, that is given to a runner.&lt;/p&gt;
&lt;h3 id="runner"&gt;Runner&lt;/h3&gt;
&lt;p&gt;A runner is a server, running Linux, that will take what you wrote in your pipeline and setup all the processes in order to accomplish what you told it.&lt;/p&gt;
&lt;p&gt;For example, if we said &amp;ldquo;dear runner, compile our application (given a Dockerfile) and publish it on GitLab&amp;rdquo; it will exactly do this thing.&lt;/p&gt;
&lt;p&gt;The way to communicate between us and the machine, is using a YAML file.&lt;/p&gt;
&lt;h3 id="yaml"&gt;YAML&lt;/h3&gt;
&lt;p&gt;A YAML file is a plain text file, with some instructions in there. YAML is a declarative language, meaning that we don&amp;rsquo;t have to write specific keywords in order to describe or achieve something in particular, rather than we focus more on the grammar of the language to reach our goals.&lt;/p&gt;
&lt;p&gt;To learn YAML I strongly suggest &lt;a href="https://learnxinyminutes.com/yaml/"&gt;this amazing website&lt;/a&gt; that will teach you in no time how to write some YAML.&lt;/p&gt;
&lt;h2 id="ok-how-do-i-setup-the-runner"&gt;Ok, how do I setup the runner?&lt;/h2&gt;
&lt;p&gt;Left side of the menu, &amp;ldquo;build&amp;rdquo;, &amp;ldquo;pipelines&amp;rdquo;
&lt;img src="https://dag7.it/img/gitlab-pipeline-4.png" alt="gitlab-pipeline-4.png"&gt;&lt;/p&gt;
&lt;p&gt;Next, click on the &amp;ldquo;test template&amp;rdquo;
&lt;img src="https://dag7.it/img/gitlab-pipeline-5.png" alt="gitlab-pipeline-5.png"&gt;&lt;/p&gt;
&lt;p&gt;We will be in the pipeline editor: this will create a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file at the end of our edits.
&lt;img src="https://dag7.it/img/gitlab-pipeline-6.png" alt="gitlab-pipeline-6.png"&gt;&lt;/p&gt;
&lt;p&gt;Click &amp;ldquo;commit changes&amp;rdquo; at the end and wait for a pipeline running warning at the top of the page.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-7.png" alt="gitlab-pipeline-7.png"&gt;&lt;/p&gt;
&lt;p&gt;If you click on the link in blue, you will see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-8.png" alt="gitlab-pipeline-8.png"&gt;&lt;/p&gt;
&lt;p&gt;don&amp;rsquo;t worry if something doesn&amp;rsquo;t have a green tick, it will be a matter of time.&lt;/p&gt;
&lt;p&gt;If everything goes well, everything&amp;rsquo;s will be marked in green.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-9.png" alt="gitlab-pipeline-9.png"&gt;&lt;/p&gt;
&lt;p&gt;This means that pipeline has succeeded.&lt;/p&gt;
&lt;h2 id="i-got-it-now-i-want-to-write-a-toy-pipeline-that-describes-a-tiramisu-recipe"&gt;I got it, now I want to write a toy pipeline that describes a Tiramisu recipe&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the YAML file to copy paste in the pipeline:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- prep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- assembly
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- cooling
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- serving
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepare_cream:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: prep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I beat the egg yolks with the sugar&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I add the mascarpone&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I whip the cream and fold it in&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepare_coffee:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: prep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I prepare the coffee with the Moka pot (preferably a large one)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I let the coffee cool&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepare_ladyfingers:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: prep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I prepare the ladyfingers&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;soak_ladyfingers:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: assembly
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I dip the ladyfingers in cold coffee&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;layer_layouts:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: assembly
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;Arrange the ladyfingers in the pan&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;Spread the mascarpone cream&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;Repeat the layers until the pan is full&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;Drizzle the surface with bitter coffee or chocolate&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chill_tiramisu:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: cooling
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I refrigerate the tiramisu for at least 4 hours&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;serve_tiramisu:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stage: serving
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I get the set of plates&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I plate the tiramisu&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;I serve it to my guests&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;:)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- echo &amp;#34;Measure blood sugar&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the recipe in Italian:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- preparazione_ingredienti
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- assemblaggio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- raffreddamento
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- servizio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepara_crema:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: preparazione_ingredienti
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Monto i tuorli con lo zucchero&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Aggiungo il mascarpone&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Monto la panna e la incorporo&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepara_caffe:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: preparazione_ingredienti
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Preparo il caffé con la Moka (meglio se grande)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Lascio raffreddare il caffè&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;prepara_savoiardi:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: preparazione_ingredienti
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Preparo i savoiardi&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inzuppa_savoiardi:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: assemblaggio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Inzuppo i savoiardi nel caffè freddo&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;metti_strati:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: assemblaggio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Disporre i savoiardi nella teglia&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Stendere la creama al mascarpone&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Ripetere gli strati fino a esaurire lo spazio nella teglia&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Spolverare con caffè amaro o cioccolato in superficie&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;raffredda_tiramisu:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: raffreddamento
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Metto il tiramisù in frigo per almeno 4 ore&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;servi_tiramisu:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; stage: servizio
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; script:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - date +%H%M%S
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Prendo il set di piattini&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Impiatto il tiramisù &amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Servo ai miei ospiti&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;:)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - echo &amp;#34;Misurare la glicemia&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Save it into your pipeline editor, commit and&amp;hellip;?&lt;/p&gt;
&lt;h2 id="where-tiramisu"&gt;Where Tiramisu?&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gitlab-pipeline-10.png" alt="gitlab-pipeline-10.png"&gt;&lt;/p&gt;
&lt;p&gt;We have cooked a delicious tiramisu and learnt how the pipeline works! 🍰🍫☕️&lt;/p&gt;
&lt;h2 id="ending"&gt;Ending&lt;/h2&gt;
&lt;p&gt;Thanks for your attention, I highly suggest to try it out this simple example to get started with GitLab runners and pipelines. This was a toy example, but many other awesome things can be done.&lt;/p&gt;
&lt;p&gt;Try this pipeline in your own GitLab project and share your results by sending me an email!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: the line &amp;ldquo;date&amp;rdquo; in script part, is for echoing the date time when the job is executed. This is to figure out if the job execution is done in parallel or in sequence. Figure it out for yourself, which of the two ways.&lt;/p&gt;</description></item><item><title>Django Day</title><link>https://dag7.it/posts/django-day-dk-2024/</link><pubDate>Fri, 04 Oct 2024 14:47:01 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/django-day-dk-2024/</guid><description>&lt;h1 id="the-event"&gt;The event&lt;/h1&gt;
&lt;p&gt;Django Day in Copenaghen is an event dedicated to Django, the Python web framework. It was a one-day event, and I had the chance to attend it as a speaker.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve decided to talk about Chiptune, a genre of music that uses the sound chips of old computers and consoles to create music.&lt;/p&gt;
&lt;h1 id="the-talk"&gt;The talk&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve presented a small introduction to Chiptune, explaining what it is and how it is made. I&amp;rsquo;ve also shown some examples of main artists, the demoparties, the Chiptune music, and I&amp;rsquo;ve explained how to create Chiptune music using a tracker and what&amp;rsquo;s the difference between a tracker and a DAW.&lt;/p&gt;
&lt;h1 id="the-slides"&gt;The slides&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re here, you probably would like to download the slides of my talk.&lt;/p&gt;
&lt;p&gt;Maybe you&amp;rsquo;re interested in Chiptune, or maybe you&amp;rsquo;re interested in the talk I&amp;rsquo;ve done.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dag7.it/pdf/slides/2024_djangoday_chiptune.pdf"&gt;Click here to download the slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t feel up to download the slides, &lt;a href="https://youtu.be/-msvvauZVvo?t=30793"&gt;click here to see a youtube video of me in action&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="the-feedback"&gt;The feedback&lt;/h1&gt;
&lt;p&gt;The feedback was great. I&amp;rsquo;ve received some questions about Chiptune after the talk. I talked with some people who knew artists and discovered new people doing music.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dag7.it/music"&gt;I also make music, take a look if you please!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The organizers were happy with my talk, and they&amp;rsquo;ve asked me if I would have liked to perform a live Chiptune session. I&amp;rsquo;ve accepted, and I&amp;rsquo;ve performed a small live session at the end of the event, using my Gameboy.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/gallery/2024_10_07_django_day_dk.jpg" alt="Django Day 2024 final pic"&gt;&lt;/p&gt;</description></item><item><title>Dungeon Devlog #5</title><link>https://dag7.it/posts/devlog-5/</link><pubDate>Mon, 10 Jun 2024 23:47:02 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/devlog-5/</guid><description>&lt;p&gt;I am caught up in something else and have been slowing down these days.&lt;/p&gt;
&lt;p&gt;The situation has become untenable: I feel the need to write tests and modularize the code further.&lt;/p&gt;
&lt;p&gt;Things break and I don&amp;rsquo;t know why.&lt;/p&gt;
&lt;p&gt;Anyway, &lt;strong&gt;I manage to create a small inventory&lt;/strong&gt; by deciding to treat the inventory as a dictionary and inserting an object into it every time it is printed in the overlay.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a problem: &lt;strong&gt;exits are added to the inventory&lt;/strong&gt;, that it is not what we want, but never mind: this is a problem I will fix another time.&lt;/p&gt;
&lt;p&gt;I also decide to implement the fact that &lt;strong&gt;enemies counter-attack&lt;/strong&gt; by assigning each monster an attack and a defense and making it so that when they counter-attack and when I attack, according to small mathematical formulas the hp is decreased or not.&lt;/p&gt;
&lt;p&gt;To get around the regeneration problem I temporarily decide to &lt;strong&gt;make the character recover one hp every time he moves&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I also decide to implement the fact that &lt;strong&gt;the character can die&lt;/strong&gt;: if the hp is less than 0, the game ends. To start a new game, just press the &amp;ldquo;R&amp;rdquo; key.&lt;/p&gt;
&lt;p&gt;The game is starting to take shape, but I have to &lt;strong&gt;fix some bugs and make it more playable&lt;/strong&gt;, for now I&amp;rsquo;d like to polish on textures and make the game more enjoyable, so I manage to understand when to use border&amp;rsquo;s tileset and when not.&lt;/p&gt;
&lt;p&gt;Other wishable features are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;handle items in the inventory&lt;/li&gt;
&lt;li&gt;fix enemies texture bug&lt;/li&gt;
&lt;li&gt;add proper tiles for the border in the map&lt;/li&gt;
&lt;li&gt;invent a story&lt;/li&gt;
&lt;li&gt;add a boss / boss room&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am very happy with the progress I made, but I have to keep going.&lt;/p&gt;</description></item><item><title>Dungeon Devlog #4</title><link>https://dag7.it/posts/devlog-4/</link><pubDate>Fri, 07 Jun 2024 22:35:13 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/devlog-4/</guid><description>&lt;p&gt;Tonight is the night! I need to implement &lt;strong&gt;graphics&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Well, how to do it? Old videogames were made with spritesheets, so I decide to do the same. I downloaded a spritesheet from a free itch.io download link, and I am ready to go&amp;hellip;?&lt;/p&gt;
&lt;p&gt;But what&amp;rsquo;s the basic idea? I have to &lt;strong&gt;draw the map exactly as I did&lt;/strong&gt; before, but &lt;strong&gt;instead of drawing colored squares&lt;/strong&gt;, I have to draw textures.&lt;/p&gt;
&lt;p&gt;The steps are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;load the spritesheet&lt;/li&gt;
&lt;li&gt;while drawing the map, if the tile is a wall then go to the spritesheet and take the 4th square by row and column
&lt;ol&gt;
&lt;li&gt;for example, if the wall is at row 1 and column 1, then the square is at row 0, column 0, wide 16 and high 16&lt;/li&gt;
&lt;li&gt;if the character is at row 2 and column 1, then the square is at row 16&lt;em&gt;1 and column 1&lt;/em&gt;16, wide 16 and high 16, and so on&lt;/li&gt;
&lt;li&gt;this is because the spritesheet is 16x16 and every square is 16x16&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is feasible, so I decide to go ahead: I modify the main structure by adding row column and spritesheet where the graphics are saved.&lt;/p&gt;
&lt;p&gt;After that, &lt;strong&gt;instead of drawing colored squares I decide to draw textures&lt;/strong&gt;, each 16x16 and&amp;hellip; it&amp;rsquo;s a great idea, everything works, I just have to be careful to change the sprites of the enemies.&lt;/p&gt;
&lt;p&gt;Wouldn&amp;rsquo;t it be nice a &lt;strong&gt;minimap in the HUD too&lt;/strong&gt;? Of course, it may come in handy for me for debugging purposes but also for the player in the future.&lt;/p&gt;
&lt;p&gt;I notice that &lt;strong&gt;minimap is the same map I normally draw&lt;/strong&gt;, but &lt;strong&gt;with pixels 1x1&lt;/strong&gt; instead of tiles. Basically there is no need to rewrite the code, just to make a function that draws a general map.&lt;/p&gt;
&lt;p&gt;Since the code is starting to be a mess, I decide to refactor it a bit: dictionary will store each element&amp;rsquo;s characteristics, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enemy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;y&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;hp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;attack&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;walkable&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Look how it&amp;rsquo;s beautiful!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/dungeon6.png" alt="dungeon6.png"&gt;&lt;/p&gt;
&lt;p&gt;Now &lt;strong&gt;it&amp;rsquo;s time to improve the HUD&lt;/strong&gt; and set health points and attack points to the protagonist and enemies.&lt;/p&gt;
&lt;p&gt;I decide to also change the function that inserts stuff into the map: in case of enemies/living people, it also inserts additional parameters such as residual hp or collected tool, so that I can manage enemies&amp;rsquo; items and death as well.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/dungeon7.png" alt="dungeon7.png"&gt;&lt;/p&gt;
&lt;p&gt;I finally decide to implement a simple level up (experience) and level up mechanism, by using some math functions and randomness.&lt;/p&gt;</description></item><item><title>Dungeon Devlog #3</title><link>https://dag7.it/posts/devlog-3/</link><pubDate>Thu, 06 Jun 2024 23:46:23 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/devlog-3/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Good morning Night City
-Cyberpunk 2077&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My morning is not a morning, but an evening, and it starts after a good sip of caffè latte: I am ready to face the day. I have a lot of ideas in my head and I want to make them reality.&lt;/p&gt;
&lt;p&gt;I had an interesting discussion some time ago with some friends of mine about the difference of cappuccino, caffè latte, and latte macchiato. I am not a coffee expert, but I knew that the difference is in the amount of milk and coffee. The articles I read on the internet are not very clear, however &lt;a href="https://www.caffeborbone.com/gb/en/magazine-segreti-di-caffe/differenza-tra-cappuccino-latte-macchiato-e-caffelatte.html"&gt;this article here&lt;/a&gt; explained by &amp;ldquo;nientepopodimeno&amp;rdquo; but Caffè Borbone is very clear and I recommend it to you if you&amp;rsquo;re interested.&lt;/p&gt;
&lt;p&gt;We need first to resolve &lt;strong&gt;the performance problem&lt;/strong&gt;: a dear friend of mine advised me to &lt;strong&gt;reduce the size of the map&lt;/strong&gt; since I would make less effort that way. I decide to throw down the whole dungeon generation algorithm and redo it almost from scratch.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve watched some videos and read some codes online, but &lt;a href="https://www.youtube.com/watch?v=fudOO713qYo"&gt;this excellent video&lt;/a&gt; brought to you by &amp;ldquo;TheZZAZZGlitch&amp;rdquo; is really interesting and explains in a visual way an approach to generate dungeons.&lt;/p&gt;
&lt;p&gt;The generation algorithm is very interesting: first it generates rooms as I do, then unlike me who immediately tries to connect them, it generates &amp;ldquo;dumb&amp;rdquo; rooms (called 1x1) and tries to connect them with existing rooms. It also does another thing: it &lt;strong&gt;generates a special border&lt;/strong&gt; (soft border) that does not allow it to be crossed or passed in any way.&lt;/p&gt;
&lt;p&gt;I reason a little bit about how to do that: generate the rooms, okay, which I already had. I can &lt;strong&gt;import the 1x1 idea&lt;/strong&gt;: sounds good to me!&lt;/p&gt;
&lt;p&gt;To my surprise it is an approach that works very well: by increasing the number of 1x1 rooms I can increase or decrease the complexity of a dungeon.&lt;/p&gt;
&lt;p&gt;Basically it is like &lt;strong&gt;connecting multiple rooms together&lt;/strong&gt;: an approach that works very well!&lt;/p&gt;
&lt;p&gt;Before I re-create the collisions and &amp;ldquo;the walkable and the unwalkable&amp;rdquo;, I want to make sure that I generate the items and everything that is needed to go from one world to another correctly.&lt;/p&gt;
&lt;p&gt;It occurs to me that I have to generate items, money, etc., and these should not be in corridors. Grr, this is difficult.&lt;/p&gt;
&lt;p&gt;Going back to the performance problem, &lt;strong&gt;I decide to reduce the size of the map to 56x32 pixels&lt;/strong&gt;. Since I did my algorithm in a way that I can change the size of the map, I can do this without any problem and with some surprise I see that the performance has improved a lot, generations are almost instantaneous.&lt;/p&gt;
&lt;p&gt;I am very happy and this is the result!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/dungeon2.png" alt="Dungeon image, with proper corridors and rooms"&gt;&lt;/p&gt;
&lt;p&gt;Things can&amp;rsquo;t stop here:** I have to generate the items and the money**. I have to generate the exit that will take me to the next level. I have to generate the enemies and some elementary game elements: key, chest, exit, enemy, boss, trap. After all, I can treat everything as walkable/not walkable as well.&lt;/p&gt;
&lt;p&gt;I create a dictionary of tuples: the name is something I know, the tuple there is number (which I will need in the final map), the &amp;ldquo;common&amp;rdquo; name, and a color that will then be replaced by a texture in the future.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;key&amp;#34;: (1, &amp;#34;key&amp;#34;, (255, 255, 0)),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;R#@*JE@&amp;#34;: (0, &amp;#34;nothing&amp;#34;, (0, 0, 0)),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The idea is to draw the map and depending on what is in the map, draw something different.&lt;/p&gt;
&lt;h2 id="the-overlapping-problem"&gt;The overlapping problem&lt;/h2&gt;
&lt;p&gt;It also occurs to me that there might be overlapping problems: however, if I calibrate the spawn order well, I should not have such problems.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;overlapping problem&lt;/strong&gt; is a problem that occurs when I spawn an item, and then I spawn an item on top of it.&lt;/p&gt;
&lt;p&gt;For example, I can safely decide to spawn enemies, chests, etc., and only after stairs, since if stairs replace an enemy, it is less serious than having an enemy replace stairs, it would make the game impossible.&lt;/p&gt;
&lt;p&gt;Graphically there is not much changes, but in practice I always have an exit and something on my map.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/dungeon3.png" alt="Dungeon image, with proper corridors and rooms"&gt;&lt;/p&gt;
&lt;h2 id="movement-and-collisions"&gt;Movement and collisions&lt;/h2&gt;
&lt;p&gt;Now we have to move on to movement and collisions: I simply have to make a &lt;strong&gt;function that checks if I can move on a certain tile&lt;/strong&gt;, and if yes then move, otherwise not. It will suffice to treat enemies as blocks and everything else as something walkable.&lt;/p&gt;
&lt;p&gt;The next step will be to define each &lt;strong&gt;entity behavior&lt;/strong&gt;. Let&amp;rsquo;s start with stairs -&amp;gt; I decide that every time a valid movement is made events happen, so I use the strategy of the boolean &amp;ldquo;moved and not moved&amp;rdquo;. It works.&lt;/p&gt;
&lt;h2 id="enemies-ai-idea"&gt;Enemies AI Idea&lt;/h2&gt;
&lt;p&gt;Now I have to deal with the AI of the enemies. I want to define &lt;strong&gt;different strategies&lt;/strong&gt;, but for now I am content with a &lt;strong&gt;&amp;ldquo;random&amp;rdquo; approach&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A first implementation is this: find all the reds, if they can move go in the direction they randomly choose. This approach in terms of memory sucks: it would be better for me in generation phase to save the position of the enemies and update it as they perform movements.&lt;/p&gt;
&lt;h2 id="bugs"&gt;Bugs&lt;/h2&gt;
&lt;p&gt;But here&amp;rsquo;s some bugs arise:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;if I decide to move on a tile that has already been chosen by an enemy, I am not a solid object so &lt;strong&gt;both I and the enemy overlap&lt;/strong&gt;.
&lt;ol&gt;
&lt;li&gt;solved in a simple way by &lt;strong&gt;assigning me the property of being solid&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;since I have defined that every object when stepped on and is &amp;ldquo;walkable&amp;rdquo; becomes a normal tile again, enemies do the same thing with stairs. &lt;strong&gt;In other words: the enemy steals the stairs!&lt;/strong&gt; This is not good and to solve it I have to handle the limit case of the stairs (between them they should not kill each other as they are all solid).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Technically, I could also change the order of generation: I now generate the rooms, generate the dumb rooms, connect them, generate the items and game elements, however, to save resources and time, I could generate the rooms, place the player, place the items generate the 1x1 tiles and then connect them.&lt;/p&gt;
&lt;p&gt;Another bug: &lt;strong&gt;enemies and I move in the same tile and overlap&lt;/strong&gt;: this is not good, and it is because I was never updating the fact that the area where I was standing was free and I had moved to another area. Instead, every time I move, &lt;strong&gt;I have to set the tile where I am as &amp;ldquo;walkable&amp;rdquo;&lt;/strong&gt; and the new one as &amp;ldquo;not walkable,&amp;rdquo; which comes from the fact that I occupy it.&lt;/p&gt;
&lt;p&gt;Another approach I came up with is to simply define whether the playing field is walkable or not.&lt;/p&gt;
&lt;h2 id="enemies-ai-lets-attack"&gt;Enemies AI: let&amp;rsquo;s attack!&lt;/h2&gt;
&lt;p&gt;The time has finally come: define the IA behind the enemies: meanwhile, I want to define three kind of enemies, one that is very stupid and keeps doing what I have been doing so far (wandering around randomly), one that is smart and chases the player, and the other that is greedy and steals everything stealable&lt;/p&gt;
&lt;p&gt;I create the AI for the first and the second kind, but not the third: I have to think about how to implement it.&lt;/p&gt;
&lt;p&gt;Now I find myself in endless dungeons. I definitely need to implement a quick attack just to make enemies disappear. For now I settle for &amp;ldquo;last key pressed is up, so I shoot up&amp;rdquo;. I can implement it by writing that the last key pressed &amp;ldquo;looks&amp;rdquo; in a certain direction, regardless of whether or not you can move.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/dungeon4.png" alt="Dungeon image, with proper corridors and rooms"&gt;&lt;/p&gt;
&lt;h2 id="hud"&gt;HUD&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s late but I can make it!&lt;/p&gt;
&lt;p&gt;I take a short break, and after a while, I find out about &lt;code&gt;pr.end_mode_2d()&lt;/code&gt; which allows you to draw a HUD.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s fantastic! In the top left corner I want the stats counter in general, and at the bottom I want a textbox: the messages go away after two seconds (120 then, because I&amp;rsquo;m at 60 frames per second) and the hud has to disappear.&lt;/p&gt;
&lt;p&gt;It occurs to me to make a buffer for the messages, and eventually show it slowly by removing each string.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example and why I told the 120 frames per second thing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;messages_buffer.insert(0, [&amp;#34;Level up! You are now level &amp;#34; + str(player[&amp;#39;level&amp;#39;]), 120, pr.GREEN])
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Messages are placed in a list, and each message is a list of three elements: the message, the number of frames it has to stay, and the color.&lt;/p&gt;
&lt;p&gt;At the end of the game loop, I check if the message has to be removed, and if so, I remove it, otherwise decrease the number of frames it has to stay until it reaches 0 and shows the message in the box.&lt;/p&gt;
&lt;p&gt;This is the result:
&lt;img src="https://dag7.it/img/videogames-devlog/dungeon5.png" alt="Dungeon with HUD"&gt;&lt;/p&gt;</description></item><item><title>Dungeon Devlog #2</title><link>https://dag7.it/posts/devlog-2/</link><pubDate>Wed, 05 Jun 2024 22:24:00 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/devlog-2/</guid><description>&lt;p&gt;My original idea was to &lt;strong&gt;make a dungeon game&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Damn bro, you just started and you already want to make a dungeon game?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Yes, I know, but I love dungeon games, and I want to make my own since ever. The most fun part of a dungeon game is the dungeon itself: the rooms, the corridors, the monsters, the traps, the inventory. &lt;strong&gt;Everything is random&lt;/strong&gt;, everything is different every time you play, and &lt;strong&gt;that&amp;rsquo;s addicting&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But, let&amp;rsquo;s go back to the game.&lt;/p&gt;
&lt;p&gt;It is time to make my hands dirty on the actual dungeon creation. Where do I start?&lt;/p&gt;
&lt;p&gt;Well, I had seen a video a while back on procedural dungeon map generation. The idea was that &lt;strong&gt;first you generated rooms, then you generated corridors&lt;/strong&gt;. I then decide to set a scary size for the map, &lt;strong&gt;like 300x300&lt;/strong&gt; because I think it is a good size for a dungeon.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s move on the dungeon generator part: &lt;strong&gt;it is slow and has problems&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The idea is to generate the whole map first by defining walkable and non-walkable areas, the player (always a yellow square), draw a green square for each &amp;ldquo;non walkable square&amp;rdquo;, then I can move on to fill the entire map with monsters, items, and traps&amp;hellip; you know, the usual dungeon stuff.&lt;/p&gt;
&lt;p&gt;It works but&amp;hellip; the problem is also that &lt;strong&gt;I can&amp;rsquo;t see anything this way&lt;/strong&gt;, because everything is too big.&lt;/p&gt;
&lt;p&gt;I find out about the existence of the game &amp;ldquo;camera&amp;rdquo; which serves just as if it were a separate and detached window to the game world. Very pleased about this, I decide to &lt;strong&gt;postpone the problem of optimizing things and make them faster until the next day&lt;/strong&gt;, not before adding some small debugging controls (W and S keys, zoom in or out the view)&lt;/p&gt;
&lt;p&gt;I also implemented a small collider with walls, that does not seem to work properly and the classic directional arrow controls for moving my yellow square around.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the result:
&lt;img src="https://dag7.it/img/videogames-devlog/dungeon1.png" alt="Dungeon image at the end of devlog 2, with corridors very stretchy or clumsy"&gt;&lt;/p&gt;</description></item><item><title>Dungeon Devlog #1</title><link>https://dag7.it/posts/devlog/</link><pubDate>Tue, 04 Jun 2024 21:13:25 +0200</pubDate><author>dag7+ifyourenotallmpleaseremovethis@protonmail.com (Dag)</author><guid>https://dag7.it/posts/devlog/</guid><description>&lt;p&gt;Finally, after some years, I am experimenting for the first time with making video games.&lt;/p&gt;
&lt;p&gt;I have always been fascinated by the idea of creating a video game, but I have never had the courage to start. I have always been afraid of not being able to finish it, of not being able to make it as I wanted, of not being able to make it fun.&lt;/p&gt;
&lt;p&gt;But this time things are different: I wanted to make a game for GBA, but thanks to a friend of mine who suggested me to use Raylib, a C library for making games, I decided to start with that.&lt;/p&gt;
&lt;p&gt;Honestly I was intimidated by the idea of starting from scratch, because many frameworks nowadays I thought were too complex for me. But Raylib is damn simple, and I like it.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t make games from one day to another, it requires a lot of time, work, programming, testing and all the other software development phases. After all I write software for a living, so I know what I am talking about.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with a silly thing and make Totti&amp;rsquo;s Quest, a red square that if it touches another green square, the other one turns yellow and starts the Roma anthem + an image of Totti&lt;/p&gt;
&lt;p&gt;The first problem is &lt;strong&gt;drawing a square&lt;/strong&gt;. Well, just check raylib lib! But raylib is a library in C.&lt;/p&gt;
&lt;p&gt;My main language is Python: it&amp;rsquo;s not &amp;ldquo;I don&amp;rsquo;t like C&amp;rdquo;, it&amp;rsquo;s more like &amp;ldquo;I use Python every single day, so I am confident with it&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;They are programming languages: exactly like with the normal ones, they work in the same way. The only difference is that C is verbose, I need to manage more things (like structs, dictionaries are not native and so on). Python have a lot of gimmicks that make it easier to use. Since the result is gonna be the same, I decided to use the latter.&lt;/p&gt;
&lt;p&gt;Fortunately, raylib was ported to Python so you find these &amp;ldquo;bindings&amp;rdquo; that basically make the library suitable for a language that is different from the original one.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve managed to complete the code with a bit of a problem: I &lt;strong&gt;can&amp;rsquo;t get the audio to work&lt;/strong&gt; because it always clashes.&lt;/p&gt;
&lt;p&gt;It occurs to me that I can use &lt;strong&gt;boolean variables&lt;/strong&gt; to indicate states, like &amp;ldquo;played&amp;rdquo; or not.&lt;/p&gt;
&lt;p&gt;This is an approach that works, and I am happy with it.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://dag7.it/img/videogames-devlog/tottisquest.png" alt="Green square and yellow square"&gt;&lt;/p&gt;</description></item></channel></rss>