<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Github on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/github/</link><description>Recent content in Github on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Mon, 11 Nov 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/github/index.xml" rel="self" type="application/rss+xml"/><item><title>Website in a Docker Container</title><link>https://blog.iankulin.com/website-in-a-docker-container/</link><pubDate>Mon, 11 Nov 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/website-in-a-docker-container/</guid><description>&lt;p&gt;Having figured out how to use the GitHub package registry, I was a bit inspired by &lt;a href="https://lipanski.com/posts/smallest-docker-image-static-website"&gt;this blog post&lt;/a&gt; from Florin Lipan to deliver all my little static websites as Docker containers. I&amp;rsquo;m not as focused as he is about making them tiny, but I did steal the idea of using &lt;a href="https://busybox.net/about.html"&gt;BusyBox&lt;/a&gt; httpd for serving them, resulting in about 4MB containers. That&amp;rsquo;s small enough for me, and since they are all very similar, there&amp;rsquo;s a fair bit of layer reuse going on.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the setup. I dump the static (html, css, js etc) files for the website into a &amp;lsquo;www&amp;rsquo; sub-directory.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-6.55.02-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-6.55.02-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The dockerfile pulls in BusyBox then copies those files into the container. Note these are in the container, it&amp;rsquo;s not going to be bound to an external directory (where we could change them), the container carries its website files with it. Any change to the website content will require a container rebuild.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EXPOSE 80&lt;/code&gt; doesn&amp;rsquo;t really do anything, it&amp;rsquo;s pretty much just documentation. Then the &lt;code&gt;CMD&lt;/code&gt; directive starts the server on port 80 and points to the static files that we copied in earlier.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FROM busybox&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;latest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# Create the directory for the web content, and copy files in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RUN mkdir &lt;span style="color:#81a1c1"&gt;-&lt;/span&gt;p &lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;www&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COPY www&lt;span style="color:#81a1c1"&gt;/.&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;var&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;www&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;html
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# Expose port 80 for the web server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXPOSE &lt;span style="color:#b48ead"&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# Start the httpd server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;CMD &lt;span style="color:#eceff4"&gt;[&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#34;sh&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;-c&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;busybox httpd -f -p 80 -h /var/www/html&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To use this dockerfile to build our container, just docker build it and give it a tag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker build -t ghcr.io/iankulin/example.com:latest .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then if we run it, and go to http://localhost, there&amp;rsquo;s our website.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --name httpd-example.com -p 80:80 ghcr.io/iankulin/example.com:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-7.15.11-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-7.15.11-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="with-nginx-proxy-manager"&gt;With NGINX Proxy Manager&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; file I use on the VPS host is slightly more complicated. We want each of the website containers to run in the same docker network as Nginx Proxy Manager - since docker networks have their own little dns server based on the container names, that&amp;rsquo;s going to make hooking it up trivial.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; example.com:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; container_name: httpd-example.com
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: ghcr.io/iankulin/example.com:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; restart: unless-stopped
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - nginx-proxy-manager_default
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;networks:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nginx-proxy-manager_default:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; external: true
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="architecture"&gt;Architecture&lt;/h3&gt;
&lt;p&gt;Since I develop on an M1 MacBook, but host all my workloads on regular AMD64 Linux LXC containers or VMs, I need to build for that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker build --platform linux/amd64 -t ghcr.io/iankulin/example.com:latest .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In actual fact, I could have built that way for the Mac as well - Docker Desktop would have just run it in a Linux VM with a small performance penalty which wouldn&amp;rsquo;t be noticeable for my purposes. Once it&amp;rsquo;s built, we push it up to the GitHub Container Registry.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker push ghcr.io/iankulin/example.com:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Working with the registry is well covered in my previous post, so I won&amp;rsquo;t go into those details here.&lt;/p&gt;
&lt;h3 id="on-the-host"&gt;On the host&lt;/h3&gt;
&lt;p&gt;On the host where the website is to run, I just make a directory for it and drop the &lt;code&gt;docker-compose.yml&lt;/code&gt; in. Then &lt;code&gt;docker compose up -d&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-7.46.31-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-7.46.31-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;re running in the Nginx Proxy Manager docker network, when we specify the host name for the new web site for NPM to proxy to, it&amp;rsquo;s just the container name we gave it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-8.06.44-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-8.06.44-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then the DNS settings for your domain need to be pointed to this host. Once that&amp;rsquo;s propagated, you&amp;rsquo;ll be able to request the SSL certificate in NPM and your website is live.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-8.11.23-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-19-at-8.11.23-pm.png" width="886" alt=""&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Using the GitHub Container Registry</title><link>https://blog.iankulin.com/using-the-github-container-registry/</link><pubDate>Mon, 04 Nov 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/using-the-github-container-registry/</guid><description>&lt;p&gt;As the number of little projects I&amp;rsquo;m running on VPSs grows, I need to have a regimented system for managing all that. I could be using something like &lt;a href="https://coolify.io/"&gt;Coolify&lt;/a&gt;, but, at least for the moment, I&amp;rsquo;d rather build my own system.&lt;/p&gt;
&lt;p&gt;Currently my system is Nginx Proxy Manager (dockerised) in front of each app. If it&amp;rsquo;s a static website, that&amp;rsquo;s another dockerised Nginx, started with a compose file and with &lt;code&gt;www&lt;/code&gt; and &lt;code&gt;conf&lt;/code&gt; sub-directories that I&amp;rsquo;ve &lt;code&gt;git pull&lt;/code&gt;ed from the project. It&amp;rsquo;s not pretty.&lt;/p&gt;
&lt;p&gt;It occurs to me that I could just be bundling each static website &lt;em&gt;inside&lt;/em&gt; a Docker image, then the only content for each website on the VPS would be a compose file. This has the extra appeal that eventually I could use GitHub CI/CD to rebuild the container so changing a website would be pushing my edits to main, then &lt;code&gt;compose down&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, and &lt;code&gt;up&lt;/code&gt; on the VPS.&lt;/p&gt;
&lt;p&gt;Currently I&amp;rsquo;ve only been using DockerHub for my containers, but the free plan only allows for a single private image, whereas on GitHub the free plan doesn&amp;rsquo;t have a number of packages limit - rather it has a total storage (500MB) and monthly transfers (1GB) &lt;a href="https://docs.github.com/en/billing/managing-billing-for-your-products/managing-billing-for-github-packages/about-billing-for-github-packages"&gt;limits&lt;/a&gt;. Along with the aforementioned integration with GitHub CI/CD, this makes it the obvious place to store these images until my scale is large enough to set up my own registry (which I would probably do with &lt;a href="https://forgejo.org/"&gt;Forgejo&lt;/a&gt; on a VPS since the limits of running that inside my Tailscale network is starting to be a friction point anyway).&lt;/p&gt;
&lt;p&gt;Long story short - I want to start using the GitHub container registry, and this post steps through that.&lt;/p&gt;
&lt;h2 id="access-tokens"&gt;Access Tokens&lt;/h2&gt;
&lt;p&gt;If you set up your Docker Hub a while ago, you&amp;rsquo;ve probably forgotten that early on, you had to log into it from the command line with the &lt;code&gt;docker login&lt;/code&gt; command. With Docker Hub, that&amp;rsquo;s your usual username/password combo, but GitHub has a more fine-grained system of permissions, where you generate &amp;lsquo;Personal Access Tokens&amp;rsquo;. This is quite cool, for example you can generate a token with add/update/delete access for your main development laptop, but then generate a different token that only has read access to use on the server where you need to deploy the image.&lt;/p&gt;
&lt;p&gt;The Personal Access Token (PAT) is just used in place of a password when you log in. As well as the benefit of being able to control the permissions for each PAT when you create it, you also name them. This would be helpful for example if your software lead had their laptop stolen, and you needed to revoke the PAT for that device. It&amp;rsquo;s also possible to set expiry dates for the PATs.&lt;/p&gt;
&lt;p&gt;Generating the PATs is done in:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GitHub | Profile | Settings | Developer Settings (left column, bottom) | Personal Access Tokens | Tokens Classic | Generate Access Token Classic&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you have MFA set up (you should) it will ask for that. Then give it a &amp;lsquo;Note&amp;rsquo; and the permissions you want for &amp;ldquo;Packages&amp;rdquo; - Container images are stored in the &amp;ldquo;Packages&amp;rdquo; section of GitHub (where it&amp;rsquo;s also possible to store other artifacts such as your private NPM packages). In the example below we&amp;rsquo;ve asked for Read/Write/Delete access.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-11.49.54-am.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-11.49.54-am.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once that&amp;rsquo;s completed, you&amp;rsquo;ll be shown a list of your existing PATs, plus the new one you&amp;rsquo;ve just generated. This is the only time it will ever be displayed in GitHub, so you need to copy it out to where you need it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-11.50.11-am.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-11.50.11-am.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="logging-in"&gt;Logging in&lt;/h2&gt;
&lt;p&gt;Before we can push an image to the GitHub Container Registry (ghcr.io) we&amp;rsquo;ll need to use this PAT to log in. I&amp;rsquo;m using the command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker login --username &amp;lt;github username&amp;gt; --password &amp;lt;PAT we just generated&amp;gt; ghcr.io
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ghcr.io&lt;/code&gt; is just the URI for the container registry. It will complain about you pasting the PAT in the command line like that - I guess it&amp;rsquo;s in your bash history now. I&amp;rsquo;ll leave you to google how to do that more securely.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.02.37-pm.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Note that you can be logged into several container registries at once. Logging into the ghcr.io won&amp;rsquo;t mean that you&amp;rsquo;ll need to re-logging to DockerHub later; that will still work fine.&lt;/p&gt;
&lt;h2 id="pushing"&gt;Pushing&lt;/h2&gt;
&lt;p&gt;Once that&amp;rsquo;s done, you can push images just as you are used to with DockerHub, with the exception that you need to specify the container registry as part of your image name. It&amp;rsquo;s possible to do that with &lt;code&gt;hub.docker.com&lt;/code&gt; as well, but Docker privileged themselves to make it a default. To use a different registry (in our case ghcr.io) it needs to be included in the image name, along with your GitHub use name.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker push ghcr.io/&amp;lt;github user name&amp;gt;/&amp;lt;container name&amp;gt;:&amp;lt;tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.08.50-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;If you head to GitHub, and go into &amp;ldquo;Packages&amp;rdquo; instead of &amp;ldquo;Repositories&amp;rdquo;, your container will be there.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.24.10-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.24.10-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="pulling"&gt;Pulling&lt;/h2&gt;
&lt;p&gt;Pulling the container is going to be even simpler, log in to the registry with the same command we used above, then just docker pull with the registry in the container name - exactly as suggested in the package page on GitHub above.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker pull ghcr.io/&amp;lt;github user name&amp;gt;/&amp;lt;container name&amp;gt;:&amp;lt;tag&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.29.33-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-06-at-12.29.33-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Getting Your Vite React App to Work on Github Pages</title><link>https://blog.iankulin.com/getting-your-vite-react-app-to-work-on-github-pages/</link><pubDate>Fri, 26 Jan 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/getting-your-vite-react-app-to-work-on-github-pages/</guid><description>&lt;img src="https://blog.iankulin.com/images/combined.png" width="512" alt=""&gt;
&lt;p&gt;One of the many cool things about GitHub is &lt;a href="https://pages.github.com"&gt;GitHub Pages&lt;/a&gt; - the free web hosting Microsoft gives you while they vacuum up &lt;a href="https://docs.github.com/en/copilot/overview-of-github-copilot/about-github-copilot-individual"&gt;your code for CoPilot&lt;/a&gt; training. Each repository you keep there can have pages at &lt;code&gt;&amp;lt;your-github-username&amp;gt;.github.io/&amp;lt;repo-name&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="github"&gt;GitHub&lt;/h3&gt;
&lt;p&gt;To enable this, you need to go into the settings for the repository - look down the left for &amp;ldquo;Pages&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-1.58.05-pm.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to have it based on a complicated GitHub action (where your build step happens on GitHub when you push your code), but the easiest thing is just to have it deployed from a branch. To do this you choose which branch (usually main) and whereabouts in the main branch your HTML is. The choices are in the root of your project, or in the &lt;code&gt;/docs&lt;/code&gt; directory. I&amp;rsquo;ve chosen the &lt;code&gt;/docs&lt;/code&gt; directory in the screenshot above, since my messy React project is in the root.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all the GitHub set up we need. Now whenever I push my project to the &lt;code&gt;main&lt;/code&gt; branch on GitHub, whatever is in the &lt;code&gt;/docs&lt;/code&gt; directory will be uploaded to my GitHub page for this repo.&lt;/p&gt;
&lt;h3 id="vitereact"&gt;Vite/React&lt;/h3&gt;
&lt;p&gt;Now we need to make a couple of changes to our project to get this to work. The first is to tell Vite the &amp;ldquo;base directory&amp;rdquo; for the project which needs to be the repo name you&amp;rsquo;ve used on GutHub.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.04.50-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.04.50-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is written into the &lt;code&gt;index.html&lt;/code&gt; that is built as part of this process. If it&amp;rsquo;s not there, then any browser accessing your &lt;code&gt;index.html&lt;/code&gt; on gh-pages won&amp;rsquo;t be able to find your JavaScript, and the user will be left looking at a blank white page instead of your amazing app.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.11.06-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.11.06-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My process from this point, is to build the project with &lt;code&gt;npm run build&lt;/code&gt;. By default, this creates a &lt;code&gt;/dist&lt;/code&gt; directory in your project (which is already added to &lt;code&gt;.gitignore&lt;/code&gt;) and puts the project artifacts (the HTML, JavaScript, CSS and any images) into it. I then manually copy the artifacts over to the &lt;code&gt;/docs&lt;/code&gt; directory of the project and push it up to GitHub to be published - which takes two or three minutes.&lt;/p&gt;
&lt;p&gt;I like this manual step of copying the files over so that publishing is an intentful action on my part, and also, for solo projects I generally just work out of the main branch rather than on feature branches that then get PR&amp;rsquo;d into main. If you did want the process to be more CI/CD flavoured, you can just make another change the &lt;code&gt;vite.config.ts&lt;/code&gt; file to have your builds go straight to the &lt;code&gt;/docs&lt;/code&gt; folder.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;import &lt;span style="color:#eceff4"&gt;{&lt;/span&gt; defineConfig &lt;span style="color:#eceff4"&gt;}&lt;/span&gt; from &lt;span style="color:#a3be8c"&gt;&amp;#39;vite&amp;#39;&lt;/span&gt;import react from &lt;span style="color:#a3be8c"&gt;&amp;#39;@vitejs/plugin-react&amp;#39;&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;//&lt;/span&gt; https&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;//&lt;/span&gt;vitejs&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;dev&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;config&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;export&lt;/span&gt; default defineConfig&lt;span style="color:#eceff4"&gt;({&lt;/span&gt; base&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;/mosh-expense/&amp;#34;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; plugins&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[&lt;/span&gt;react&lt;span style="color:#eceff4"&gt;()],&lt;/span&gt; build&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt; outDir&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;docs&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;}})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once all that&amp;rsquo;s working, and you&amp;rsquo;ve pushed your changes and waited a minute or two, your project should be live to the world on &lt;code&gt;github.io&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.45.26-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.45.26-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you want users browsing your repo to find the live version, it&amp;rsquo;s worth editing your repository about settings to point to it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.47.30-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-12-31-at-4.47.30-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Git - pushing to two remotes</title><link>https://blog.iankulin.com/git-pushing-to-two-remotes/</link><pubDate>Fri, 15 Dec 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/git-pushing-to-two-remotes/</guid><description>&lt;p&gt;I am loving running a local Gogs instance - it&amp;rsquo;s nice pushing my git repos to a totally private hub that I know is backed up with all my other self-hosted infrastructure.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;rsquo;s good reasons to have code in GitHub as well - my build-in-public philosophy, the vague possibility that some of it might be useful to someone, my contribution to our future AI overlords, and when I need to make some code linkable - for example from one of these posts. And of course there&amp;rsquo;s this bit of social-engineering which I assume was inspired by the bathroom decor in &lt;a href="https://i.pinimg.com/originals/94/23/85/9423854153f55938c454a061ad5462fe.gif"&gt;Veronica Mars&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-25-at-5.45.50-am.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Git is an amazing tool, so of course this is possible. Normally my workflow is that I &lt;code&gt;git init&lt;/code&gt; whenever I&amp;rsquo;m working on a new something, then at some point I think &amp;ldquo;I should really push all this so it&amp;rsquo;s backed up&amp;rdquo;. I create the repository for it on GitHub or Gogs via the web interface, then come back to my project and:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git remote add origin git@github.com:IanKulin/test.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This is making the connection between my local project and the GitHub repo. I&amp;rsquo;d never really thought about what &lt;code&gt;origin&lt;/code&gt; meant in this context the hundreds of times I&amp;rsquo;ve previously typed it in, but actually it&amp;rsquo;s just the name we are giving to this connection. It&amp;rsquo;s just a convention to call it &amp;lsquo;origin&amp;rsquo;, it could just as easily be called &amp;lsquo;fred&amp;rsquo; or &amp;lsquo;github&amp;rsquo;. Since I am now planning to push to two separate remotes, it&amp;rsquo;s going to make sense to give them meaningful names. So in that case, we can do this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote add github git@github.com:IanKulin/test.git
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git remote add gogs http://ct-gogs/iankulin/test.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, we can push with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push github main
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push gogs main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You might be wondering what happens if you just do a &lt;code&gt;git push&lt;/code&gt; at this stage (or as I like to call it &amp;ldquo;&lt;em&gt;Pressing the &amp;lsquo;Publish Branch&amp;rsquo; button on the VS Code source control panel&amp;rdquo;&lt;/em&gt;). The answer is that at the command line you&amp;rsquo;ll get an error saying you haven&amp;rsquo;t specified the destination, or in VS Code, it will ask you which one.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-25-at-9.41.08-am.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;We can set the default remote with the -u flag when we&amp;rsquo;re pushing&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push -u gogs main
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-11-25-at-9.46.26-am.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Now the button in VS Code will say something &amp;ldquo;Sync Changes&amp;rdquo; and when you press it, it will only push to the remote we used in the last &lt;code&gt;-u&lt;/code&gt; push. Same thing if we &lt;code&gt;git push&lt;/code&gt; at the command line - it will work, but only push to the remote we used in the last &lt;code&gt;-u&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also worth noting that when we&amp;rsquo;ve set the default remote with the &lt;code&gt;-u&lt;/code&gt; flag in a &lt;code&gt;push&lt;/code&gt;, it is also the default remote for pulling from. Essentially this remote becomes the source-of-truth.&lt;/p&gt;
&lt;p&gt;For me this setup is usually fine - I&amp;rsquo;m generally working on my local gogs remote, that&amp;rsquo;s the source of truth so I specify it as the default with the &lt;code&gt;push -u&lt;/code&gt;. Then, when I&amp;rsquo;m done, I manually push to github so I can share it. If it was a project I needed to work on with anyone else, that would have to be the other way around - I&amp;rsquo;d use GitHub (or GitLab, Bitbucket etc) as the source of truth, and probably not even worry about hosting a copy on my home network unless I was worried about the repo being deleted.&lt;/p&gt;</description></item><item><title>New Project Routine</title><link>https://blog.iankulin.com/new-project-routine/</link><pubDate>Sat, 21 Oct 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/new-project-routine/</guid><description>&lt;p&gt;I have a sort of muscle memory for starting little web projects now. I seem to have landed on node/express SSR apps with HTMX sprinkles. So it goes a bit like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a working directory - all lower case with a simple, but unlikely to be duplicated by me, name.&lt;/li&gt;
&lt;li&gt;Open the directory in vscode&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm init&lt;/code&gt; in the directory to create the &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;create a &lt;code&gt;public&lt;/code&gt; sub directory, and drop &lt;a href="https://htmx.org/docs/#installing"&gt;&lt;code&gt;htmx.min.js&lt;/code&gt;&lt;/a&gt; in there, and create a &lt;code&gt;styles.css&lt;/code&gt; there. I&amp;rsquo;m always conflicted about what to do about this htmx dependency. I&amp;rsquo;d rather host it rather than use their CDN because &lt;a href="https://blog.wesleyac.com/posts/why-not-javascript-cdn"&gt;reasons&lt;/a&gt;. But I also feel bad about committing it on Github. I could .gitignore it, but then when I clone the project on the production server I&amp;rsquo;d need to add another step to download it. HTMX is only 44K, and Microsoft can afford the bandwidth, so for the moment I commit them, but I need a better solution for the future.&lt;/li&gt;
&lt;li&gt;using the git tools in vscode, add &lt;code&gt;.DS_Store&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; (which also creates it), then edit it to also ignore &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install express&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install ejs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;create a server.js, and add the &lt;a href="https://nodejs.org/en/docs/guides/getting-started-guide"&gt;hello world&lt;/a&gt; code&lt;/li&gt;
&lt;li&gt;create a &lt;code&gt;readme.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;commit these files as &amp;ldquo;initial&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Create the repo on github with the same name - no readme and no licence. I do it this way for a couple of reasons - I want to find out at this point if I&amp;rsquo;ve already used this repo name, and I want it to give me the cut and paste commands to push the repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-09-25-at-9.55.46-am.png" alt=""&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do those in the terminal.&lt;/li&gt;
&lt;li&gt;Refresh the github page, and add the licence by &lt;code&gt;Add File&lt;/code&gt;, name it LICENSE - this lets you choose the template you want. What I&amp;rsquo;d really like here is &amp;ldquo;GPL3 but giant cloud companies can&amp;rsquo;t make money from hosting it&amp;rdquo; - which I guess would be called the MongoDB license or something.&lt;/li&gt;
&lt;li&gt;Do &lt;code&gt;git pull&lt;/code&gt; in the terminal to check that&amp;rsquo;s all working&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nodemon ./server.js&lt;/code&gt; then command click on the link to check everything&amp;rsquo;s working&lt;/li&gt;
&lt;li&gt;profit&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="express-skeleton"&gt;Express Skeleton&lt;/h3&gt;
&lt;p&gt;That&amp;rsquo;s my basic web app setup, but since this is an express app, and we&amp;rsquo;re using some EJS templating, there&amp;rsquo;s some other starter files I like to create. Let&amp;rsquo;s start with our pages. I&amp;rsquo;ll need an index and a 404 page, and my pages are all going to have a header section as well as a nav and a footer. Something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;─── views
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── 404.ejs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├── index.ejs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── partials
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    ├── footer.ejs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    ├── head.ejs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;   └── nav.ejs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To give you a flavour of how that all works, here&amp;rsquo;s a sample &lt;code&gt;index.ejs&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;html lang=&amp;#34;en&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;%- include(&amp;#39;./partials/head.ejs&amp;#39;) %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;%- include(&amp;#39;./partials/nav.ejs&amp;#39;) %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;div class=&amp;#34;content&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;h2&amp;gt;Hello world&amp;lt;/h3&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;%- include(&amp;#39;./partials/footer.ejs&amp;#39;) %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/body&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we need some basic routing in &lt;code&gt;server.js&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; express &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; require&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;express&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; app &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; express&lt;span style="color:#eceff4"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; hostname &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;const&lt;/span&gt; port &lt;span style="color:#81a1c1"&gt;=&lt;/span&gt; &lt;span style="color:#b48ead"&gt;3000&lt;/span&gt;&lt;span style="color:#eceff4"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;set&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;view engine&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;ejs&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;use&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;express&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;static&lt;/span&gt;&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;get&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;req&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; res&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;render&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt; title&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;Index&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1"&gt;//&lt;/span&gt;&lt;span style="color:#b48ead"&gt;404&lt;/span&gt; handling
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;use&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;function &lt;span style="color:#eceff4"&gt;(&lt;/span&gt;req&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; res&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; next&lt;span style="color:#eceff4"&gt;)&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;status&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#b48ead"&gt;404&lt;/span&gt;&lt;span style="color:#eceff4"&gt;)&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;render&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;404&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt; title&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#39;404&amp;#39;&lt;/span&gt;&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; url&lt;span style="color:#eceff4"&gt;:&lt;/span&gt; req&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;url &lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;listen&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;port&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; hostname&lt;span style="color:#eceff4"&gt;,&lt;/span&gt; &lt;span style="color:#eceff4"&gt;()&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#eceff4"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; console&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;log&lt;span style="color:#eceff4"&gt;(&lt;/span&gt;&lt;span style="color:#bf616a"&gt;`&lt;/span&gt;Server running at http&lt;span style="color:#eceff4"&gt;:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;//$&lt;/span&gt;&lt;span style="color:#eceff4"&gt;{&lt;/span&gt;hostname&lt;span style="color:#eceff4"&gt;}:&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;$&lt;/span&gt;&lt;span style="color:#eceff4"&gt;{&lt;/span&gt;port&lt;span style="color:#eceff4"&gt;}&lt;/span&gt;&lt;span style="color:#81a1c1"&gt;/&lt;/span&gt;&lt;span style="color:#bf616a"&gt;`&lt;/span&gt;&lt;span style="color:#eceff4"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#eceff4"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And, lastly, a bit of CSS to make it beautiful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@viewport {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: device-width ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; zoom: 1.0 ;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;body{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; max-width: 1200px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; font-family: Tahoma, Arial, Helvetica, sans-serif;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; margin: 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nav {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; position: fixed; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; top: 0; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width: 100%; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; overflow: hidden;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #EEE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nav li {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; display: inline-block;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; padding: 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nav a {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; display: inline;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color: #333;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text-align: center;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; padding: 17px 8px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text-decoration: none;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nav a:hover {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background: #ddd;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color: black;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nav ul {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; padding-inline-start: 4px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/* push content down below the nav bar */
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.content {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; padding: 50px 10px 10px 10px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;footer {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; width:100%;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; position:absolute;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bottom:0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; left:0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; color: #757171;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; text-align: center;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; margin: 80px auto 20px;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; background-color: #EEE;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;chefs_kiss.jpg&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-09-25-at-11.54.42-am.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Git/GutHub - macOS - marking file as executable</title><link>https://blog.iankulin.com/git-guthub-macos-marking-file-as-executable/</link><pubDate>Sun, 30 Apr 2023 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/git-guthub-macos-marking-file-as-executable/</guid><description>&lt;p&gt;I&amp;rsquo;m working on the world&amp;rsquo;s shortest shell script - it&amp;rsquo;s called by &lt;code&gt;cron&lt;/code&gt; to pull down a JSON weather report to a text file using &lt;code&gt;curl&lt;/code&gt; so I can expose it on an Nginx endpoint. The purpose is to allow me to hammer that weather API from multiple machines I control without violating the TOS of my free API key.&lt;/p&gt;
&lt;p&gt;Because I&amp;rsquo;m learning all the things, instead of just creating this on the VPS where it runs, it&amp;rsquo;s cloned from my GitHub repo for that machine. I&amp;rsquo;m creating and editing the file in VS Code on macOS, pushing to Github, then pulling the changes on the Ubuntu VPS. The intention is that this will eventually become automated with a Github action.&lt;/p&gt;
&lt;p&gt;The problem I&amp;rsquo;ve run into is that I want the file permissions so show the file is executable so when it arrives on the VPS - so no &lt;code&gt;chmod&lt;/code&gt; is required to make it usable.&lt;/p&gt;
&lt;p&gt;Some googling suggested that the executable flag (but none of the other file permissions) is stored and handled by git, and furthermore, there&amp;rsquo;s a git command to set it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git update-index --chmod=+x bin/fetchWeather.sh 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So I wrote my (one line) script, applied the command above, committed and pushed, then pulled it down on the VPS and the bit wasn&amp;rsquo;t set. So somewhere in this chain there&amp;rsquo;s a problem.&lt;/p&gt;
&lt;p&gt;At this stage, it&amp;rsquo;s helpful to know that if the executable bit is set for a file, GitHub shows this in the header of the file where it says how many lines etc.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.26.25-pm.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.26.41-pm.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;In my case, it was showing that the file was not marked as executable in GitHub, so the problem was that the &lt;code&gt;git update-index&lt;/code&gt; was not working for me for some reason.&lt;/p&gt;
&lt;p&gt;A bit more investigation turned up that there&amp;rsquo;s a setting in the &lt;code&gt;.git/config&lt;/code&gt; file called &lt;code&gt;filemode&lt;/code&gt; that controls if the originating file system executable status is preserved. That sounded promising - I was expecting to find that is was set to false, and I could change it to true, and it would fix my problem. I had a quick look and, oh, it&amp;rsquo;s already set to true.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.36.54-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.36.54-pm.png" width="656" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Seems like it&amp;rsquo;s involved though, so perhaps (my thinking went) I should change it to false and see if the problem goes away&amp;hellip;. and it did. I changed this value to &lt;code&gt;false&lt;/code&gt;, applied the executable bit with the &lt;code&gt;git update-index&lt;/code&gt; command, committed, pushed it to GitHub (it was marked executable), pulled it down to the VPS, it was still marked executable!&lt;/p&gt;
&lt;p&gt;My whole tech life, I&amp;rsquo;ve never been happy with solutions to problems where I don&amp;rsquo;t understand the underlying reasons. If things just start working when you&amp;rsquo;re fiddling around and you&amp;rsquo;re not clear on why, it feels like they could change back with just as easily and with no more reason.&lt;/p&gt;
&lt;p&gt;A clue to what&amp;rsquo;s going on (many readers will already have figured this out) was given to me by ChatGPT. When I was asking it about this issue, it kept insisting I should &lt;code&gt;chmod&lt;/code&gt; the file to be executable before I committed it. I had to be really clear with it that this wasn&amp;rsquo;t possible on macOS because it doesn&amp;rsquo;t have that sort of file permissions&amp;hellip;&lt;/p&gt;
&lt;img src="https://blog.iankulin.com/images/cain.jpg" width="140" alt=""&gt;
&lt;p&gt;Of course, in fact, it does. &lt;a href="https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/BSD/BSD.html"&gt;macOS is based on FreeBSD&lt;/a&gt; (&amp;ldquo;without the good bits&amp;rdquo; goes the old joke told at Unix conferences). I&amp;rsquo;d just somehow forgotten this - I guess in Linux I&amp;rsquo;m used to explicitly seeing them every time I look at a directory contents, but never see it on Mac. Even if you go into &amp;ldquo;Get Info&amp;rdquo; for a file in Finder on the mac, you can see the read/write permissions, but not the executable bit status.&lt;/p&gt;
&lt;p&gt;So how do you set and view the executable status on mac? Exactly the same as on any Unix.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.52.17-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2023-04-22-at-4.52.17-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I did that, and changed the /&lt;code&gt;git/config filemode&lt;/code&gt; back to &lt;code&gt;true&lt;/code&gt;. Committed and pushed the file up (without worrying about the &lt;code&gt;git update-index&lt;/code&gt;) and it showed up in GitHub as executable, pulled it down, still executable.&lt;/p&gt;</description></item><item><title>Committed</title><link>https://blog.iankulin.com/committed/</link><pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/committed/</guid><description>&lt;p&gt;I quite like logging into GitHub and seeing my commit history as the graph with the green dots. Once I get up to a year it would be a great thing to have on a T-Shirt.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-12-03-at-7.36.29-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d expect to be seeing the busy weekends, but Tuesday nights seem to be oddly productive. It could just be a start of the week energy thing - I have some other community obligations on a couple of Monday nights a month.&lt;/p&gt;
&lt;p&gt;git is an amazing tool - better that the commercial tool I used when I was programming a long way back. I really admire what the many open source programmers have put in to it. I also owe some gratitude to Microsoft for making GitHub available to newbs like me at no cost - it&amp;rsquo;s an great service.&lt;/p&gt;
&lt;p&gt;According to the graph, my first commits were on July 10. My first blog post was on the 5th, and I&amp;rsquo;m on a 154 once per day posting streak - although there&amp;rsquo;s a few two per day scattered through there when I&amp;rsquo;ve been on holidays. I&amp;rsquo;m only up to day 64 of the 100 Days of SwiftUI - so I clearly I haven&amp;rsquo;t been getting in an hour each day on that religiously, but overall, I&amp;rsquo;m pretty happy with my commitment to myself.&lt;/p&gt;</description></item><item><title>Gitting Xcode to Push</title><link>https://blog.iankulin.com/gitting-xcode-to-push/</link><pubDate>Fri, 30 Sep 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/gitting-xcode-to-push/</guid><description>&lt;p&gt;I&amp;rsquo;m very comfortable with doing all the routine git stuff from the command line, but it was bugging me that I hadn&amp;rsquo;t for the Xcode integration working. I was able to commit locally with no problem from Xcode, but could not push up to Github. It works fine from the command line, so the error about the change to a stronger SSH authentication didn&amp;rsquo;t really make sense to me.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-09-26-at-6.57.35-am.png" alt=""&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;ERROR: You&amp;rsquo;re using an RSA key with SHA-1, which is no longer allowed. Please use a newer client or a different key type&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://developer.apple.com/forums/thread/702389"&gt;This post&lt;/a&gt; from &lt;a href="https://developer.apple.com/forums/profile/pasllani"&gt;pasllani&lt;/a&gt; on the Apple Developer forums was super helpful, the only thing they missed was that you need to restart Xcode before it will work. The steps were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a new ECDSA SSH key with &lt;code&gt;ssh-keygen -t ecdsa -C &amp;quot;IanKulin@kulin.com.au&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Copy the key to the keyboard with &lt;code&gt;pbcopy &amp;lt; ~/.ssh/id_ecdsa.pub&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On Github, add the new SSH key, and while you&amp;rsquo;re there, generate a new Token in Developer Tools&lt;/li&gt;
&lt;li&gt;In XCode, delete your github account, then recreate it specifying SSH and choose the ECDSA key. It will need the access token at this stage.&lt;/li&gt;
&lt;li&gt;Restart XCode&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="other-gitgithub-posts"&gt;Other git/Github posts&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Intro to git - &lt;a href="https://blog.iankulin.com/gitting-started/"&gt;Gitting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Common git commands - &lt;a href="https://blog.iankulin.com/gitting-the-hang-of-it/"&gt;Gitting the Hang of it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.iankulin.com/gitting-up-to-date/"&gt;Merge vs rebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.iankulin.com/create-an-empty-folder-on-github/"&gt;Create an Empty Folder on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.iankulin.com/download-a-directory-from-a-github-repo/"&gt;Download a Directory from a Github repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.iankulin.com/how-to-download-a-file-from-github/"&gt;Download a File from Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>How to download a file from GitHub</title><link>https://blog.iankulin.com/how-to-download-a-file-from-github/</link><pubDate>Sat, 17 Sep 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/how-to-download-a-file-from-github/</guid><description>&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-09-13-at-9.12.31-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;A quick tip - since it was not immediately obvious to me. If you need to download a file from GitHub (as opposed to cloning it etc), look for the &amp;ldquo;Raw&amp;rdquo; button - that&amp;rsquo;s a link to the file, then right click and do whatever your browser needs to download a web resource.&lt;/p&gt;</description></item><item><title>Download a Directory from a GitHub Repo</title><link>https://blog.iankulin.com/download-a-directory-from-a-github-repo/</link><pubDate>Tue, 30 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/download-a-directory-from-a-github-repo/</guid><description>&lt;p&gt;For &lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/guess-the-flag-introduction"&gt;Challenge 2&lt;/a&gt; in the 100 days, I needed to download a directory of flag images from Paul&amp;rsquo;s GitHub. He has all the projects as sub-directories of a single &amp;ldquo;Hacking With Swift&amp;rdquo; repo. I didn&amp;rsquo;t need to whole thing, just the directory with the images.&lt;/p&gt;
&lt;p&gt;Strangely, git does not have any simple way of doing this. Neither does GitHub - I assumed the web interface would have a &amp;ldquo;download as zip&amp;rdquo; option as it does for tags.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repo"&gt;One&lt;/a&gt; of the popular solutions on StackOverflow was to use SVN, which GitHub supports and which does have this functionality. I much preferred &lt;a href="https://stackoverflow.com/users/11218031/avinash-thakur"&gt;Avinash Takur&amp;rsquo;s&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repo/70729494#70729494"&gt;suggestion&lt;/a&gt; to use GitHub&amp;rsquo;s web based VSCode.&lt;/p&gt;
&lt;p&gt;To access their VSCode, change the .com in the repo url to .dev. For example, instead of https://github.&lt;strong&gt;com&lt;/strong&gt;/twostraws/HackingWithSwift/tree/main/SwiftUI/project2, go to https://github.&lt;strong&gt;dev&lt;/strong&gt;/twostraws/HackingWithSwift/tree/main/SwiftUI/project&lt;code&gt;2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-08-22-at-6.50.16-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Once that&amp;rsquo;s done, right click on the directory to download it.&lt;/p&gt;</description></item><item><title>Gitting the hang of it</title><link>https://blog.iankulin.com/gitting-the-hang-of-it/</link><pubDate>Thu, 04 Aug 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/gitting-the-hang-of-it/</guid><description>&lt;p&gt;&lt;a href="https://xkcd.com/1597/"&gt;&lt;img src="https://blog.iankulin.com/images/git_2x.png" width="253" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I spent most of the day learning about, and practicing with git. I&amp;rsquo;ll list some of the resources at the bottom, but for the moment, this is my understandings / cheat sheet for git. Since this could conceivably turn up in someone&amp;rsquo;s google search, and slightly less conceivably be of some use, I will come back and edit it if there&amp;rsquo;s something bad/wrong here. Comments would be great if you think that&amp;rsquo;s the case.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s most likely to be useful to someone using Xcode, GitHub, and the command line for git on MacOS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start a new repository (repo)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;on GitHub create the repo, it doesn&amp;rsquo;t matter if you create any files in it - they will be wiped shortly&lt;/li&gt;
&lt;li&gt;while you are on GitHub, grab the SSH address for the repo - it&amp;rsquo;s under the green &amp;ldquo;Code&amp;rdquo; button. If your username is IanKulin and the new repo is named GitTest it would look like this &lt;code&gt;[git@github.com](mailto:git@github.com):IanKulin/GitTest.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;create your Xcode (or whatever) project. I use the repo name as the project (and therefore directory name) but that&amp;rsquo;s not strictly necessary. I navigate to the Developer folder, so the new project is created as a folder inside that. Then in terminal inside that new directory:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;that marks it as a directory under source control, I usually drop a .gitignore in at this stage (more about that further down)&lt;/li&gt;
&lt;li&gt;we need to add the files and commit them to the local git repo:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add -A&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -m &amp;quot;Initial commit&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;now we connect the local repo to your github repo&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git remote add origin [git@github.com](mailto:git@github.com):IanKulin/GitTest.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;that just sets up the name so you can use &lt;em&gt;origin&lt;/em&gt; now to refer to the remote repo&lt;/li&gt;
&lt;li&gt;push the local files up to github with&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push -u -f origin main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;main is the name of the branch - GitHub defaults to this. If you are looking at old tutorials they are probably using &lt;em&gt;master&lt;/em&gt; rather than &lt;em&gt;main.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Xcode&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;once a project is set up for git like this, Xcode will realise and use it to indicate changes in files, and mark them in the file navigator as &amp;ldquo;A&amp;rdquo; or &amp;ldquo;M&amp;rdquo; (need Added, or have been Modified). There is a Source Control menu that allows you to Add and Commit (more about these further down) to the local repo which work well, but I haven&amp;rsquo;t had any luck pushing up to GitHub with it - I do that from the command line. Doubtless this is something to do with the SSH key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;About .gitignore&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this config file is used by git to ignore the working files that shouldn&amp;rsquo;t be tracked - stuff like the different compile states and so on. Normally we&amp;rsquo;d only want the source, asset and make files etc - the stuff needed to recreate the project&lt;/li&gt;
&lt;li&gt;GitHub will create a default for the language you are using if you let it&lt;/li&gt;
&lt;li&gt;I usually add these lines to it:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;# MacOS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.DS_Store&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;to show hidden files like this in Finder, COMMAND-SHIFT-DOT and the same to rehide them&lt;/li&gt;
&lt;li&gt;if you do that, you&amp;rsquo;ll also see the .git folder which is where git does all it&amp;rsquo;s magic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;To check how things are going&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use terminal in the directory where the repo is&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;you&amp;rsquo;ll see any files changed, or that need to be added, and if the local files are ahead of the last clone/push but not if they are behind the remote (GitHub) - until you do a &lt;code&gt;git fetch&lt;/code&gt;, the local git doesn&amp;rsquo;t know what changes have happened on the remote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;To add any files you&amp;rsquo;ve created in the project to version control from the CLI&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;or of you just want to do a particular file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add&lt;/code&gt; &lt;filename&gt;&lt;/li&gt;
&lt;li&gt;this adds the files to the &amp;ldquo;staging area&amp;rdquo;  - they are having changes tracked, but they have not been &amp;ldquo;committed&amp;rdquo; to the local repository, or the remote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When done editing and adding files and they need to be &amp;ldquo;saved&amp;rdquo; to the local repository&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this is called committing them&lt;/li&gt;
&lt;li&gt;do from the XCode &lt;em&gt;Source Control&lt;/em&gt; menu, or from the CLI with&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git commit -a -m &amp;quot;Message for commit&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;now they&amp;rsquo;ve been added to the local repo. If you do a git status it will tell you you are ahead of the remote&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;To &amp;ldquo;push&amp;rdquo; all the changes up to GitHub from the CLI&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git push origin main&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;origin&amp;rdquo; is the address for the GitHub repo, it was set for us when we cloned the repo. &amp;ldquo;main&amp;rdquo; is the branch we&amp;rsquo;re pushing to.&lt;/li&gt;
&lt;li&gt;You can&amp;rsquo;t just  create a new branch with this push?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;To tag all the files in the current local repo&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git tag -a v0.2 -m &amp;quot;Second  draft&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the &lt;em&gt;v0.2&lt;/em&gt; is the tag and &lt;em&gt;&amp;ldquo;Second  draft&amp;rdquo;&lt;/em&gt; the description - change accordingly.&lt;/li&gt;
&lt;li&gt;This only does the local copy, so you need to push it to GitHub&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push --tags&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;If you go and look on GitHub, the tags appear on the right under releases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To clone from a tag point&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git clone --depth 1 --branch v0.1 [git@github.com](mailto:git@github.com):IanKulin/TagTest.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;where v0.1 is the tag&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;--depth 1&lt;/code&gt; means you don&amp;rsquo;t get all the history with it&lt;/li&gt;
&lt;li&gt;alternatively, if you don&amp;rsquo;t need all the history you could just download the zip/tarball from GitHub&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some resources&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/how-to-push-an-existing-project-to-github"&gt;How to Push an Existing Project to GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://missing.csail.mit.edu/2020/version-control/"&gt;MIT Missing Semester lecture - Version Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2"&gt;Pro Git (book)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DVRQoVRzMIY"&gt;Git Tutorial for Beginners - Git &amp;amp; GitHub Fundamentals In Depth&lt;/a&gt; (Tech with Tim video)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=USjZcfj8yxE"&gt;Learn git in 15 minutes&lt;/a&gt; - Colt Steele video&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/gb/podcast/ep-11-a-fail-story-for-every-topic/id1269435221?i=1000406471235"&gt;Fireside Swift podcast&lt;/a&gt; - Ep 11&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Create an Empty Folder on GitHub</title><link>https://blog.iankulin.com/create-an-empty-folder-on-github/</link><pubDate>Fri, 15 Jul 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/create-an-empty-folder-on-github/</guid><description>&lt;p&gt;You can&amp;rsquo;t, but you can create a folder by adding a file through the web interface and using &lt;code&gt;&amp;lt;folder name&amp;gt;/&amp;lt;file name&amp;gt;&lt;/code&gt; - so add a README.md or whatever. Then you can drag your source into the new folder as normal.&lt;/p&gt;
&lt;p&gt;I learned this from Zack West &lt;a href="https://www.alpharithms.com/how-to-create-a-folder-in-github-repos-463022/"&gt;here&lt;/a&gt;, where there is also a better explanation with pictures.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2022-07-11-at-11.11.39-am.jpg" alt=""&gt;&lt;/p&gt;</description></item><item><title>Gitting Started</title><link>https://blog.iankulin.com/gitting-started/</link><pubDate>Wed, 13 Jul 2022 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/gitting-started/</guid><description>&lt;p&gt;One of my early goals was to get in the habit of using version control with Git/Github, and I&amp;rsquo;ve got that sorted out today. My source was this excellent, very clear video from &lt;a href="https://www.youtube.com/channel/UCxA99Yr6P_tZF9_BgtMGAWA"&gt;Gwen Faraday&lt;/a&gt;. I highly recommend it if you are just starting.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/RGOj5yH7evk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;It possibly helped that I&amp;rsquo;m also on mac, so I didn&amp;rsquo;t have to deal with the &amp;ldquo;or however that&amp;rsquo;s done on your system&amp;rdquo; type problems. Also, where things didn&amp;rsquo;t work as expected, the explanation about what was being done was clear enough that the problem was solvable. For example, the push command Gwen used was:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git push origin master
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;but GitHub had defaulted my initial branch to &amp;ldquo;main&amp;rdquo; rather than &amp;ldquo;master&amp;rdquo;. Easily fixed since she immediately explained what both of those modifiers were. The only other tiny bit of troubleshooting was that my git global config wasn&amp;rsquo;t set up, so my commit was followed by a big message pointing out that my real email address wasn&amp;rsquo;t used for the commit:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Committer: User Name &amp;lt;username@Ians-MacBook-Pro.local&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Your name and email address were configured automatically based
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;on your username and hostname. Please check that they are accurate.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;You can suppress this message by setting them explicitly. Run the
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;following command and follow the instructions in your editor to edit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;your configuration file:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git config --global --edit
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;After doing this, you may fix the identity used for this commit with:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git commit --amend --reset-author
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It didn&amp;rsquo;t make any difference - the file I&amp;rsquo;d created locally pushed up to the GitHub repo just fine. When I did follow those instructions to edit the file, I suddenly needed to know how to use Vim (hint: &amp;ldquo;i&amp;rdquo; to go into insert mode for editing, then &amp;ldquo;:&amp;rdquo; for command mode and &amp;ldquo;x&amp;rdquo; to exit and save).&lt;/p&gt;
&lt;p&gt;The only real complexity in the whole process was generating the SSH key and saving that on GitHub to allow the push from your local directory up to the GitHub repository.&lt;/p&gt;
&lt;p&gt;Ignoring that, the process was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating the repository via on GitHub&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;git clone&lt;/code&gt; to download the repository to the local machine and set it up for tracking in git&lt;/li&gt;
&lt;li&gt;Edit/create the files, however. Gwen used Visual Studio code, I used my tools&lt;/li&gt;
&lt;li&gt;Check status with &lt;code&gt;git status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt; to stage the new files and freshly edited files&lt;/li&gt;
&lt;li&gt;Commit those changes with &lt;code&gt;git commit -m &amp;quot;commit title&amp;quot; -m &amp;quot;description&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then push them up to GitHub with &lt;code&gt;git push origin main&lt;/code&gt; where &amp;ldquo;main&amp;rdquo; is the branch name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that was by about the 25 minute mark in the video, and is probably enough for me to go away and get some practice with. The rest covers getting an already established local git repository to GitHub, branching, forking, undoing.&lt;/p&gt;</description></item></channel></rss>