Jekyll2024-03-25T20:42:40+00:00https://snowdrift.tech/feed.xmlSnowdrift.techPerspectives on technology, infosec, and programming. From somewhere up north in a snow drift.David Van LoonIncluding JIRA Issue Number in Commit Messages2020-04-28T01:03:03+00:002020-04-28T01:03:03+00:00https://snowdrift.tech/development/2020/04/28/including-jira-issue-number-in-commit-messages<p>The project on which I am currently working requires by convention that all commits associated with a specific JIRA issue have messages that begin with the issue number, followed by a colon and the rest of the commit message.</p>
<p>Over time, I’ve grown tired of typing (and mistyping) the issue number for each commit message, and I’ve decided to automate the process with a script.</p>
<p>The obvious place to add this functionality is in a git hook. Git hooks are scripts that are called by git at specific times, and they allow the user to customize the behavior of git. Learn more about git hooks specifically <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">here</a>.</p>
<p>Due to integration between JIRA and Bitbucket on my project, each git branch already includes the issue number of the related JIRA issue. Thus, my git hook runs at commit time and checks the branch name for a JIRA issue number. If present, it makes sure my commit message begins with the issue number.</p>
<p>I’ve used <a href="https://github.com/PowerShell/PowerShell/">PowerShell</a> as a cross-platform scripting environment, so the script should work on Windows, OSX, and Linux with minimal modifications.</p>
<p>After a bit of experimentation, I settled on the following core script:</p>
<script src="https://gist.github.com/d1vanloon/57c84e25b21ef222a5702bdd750f145a.js"></script>
<p>Due to a <a href="https://github.com/PowerShell/PowerShell/issues/16480">recent change in PowerShell</a>, this script cannot be directly used as the commit hook, so I placed this core script in a central directory for Git hooks scripts, in <code class="highlighter-rouge">C:\Tools\git-hooks\</code>.</p>
<p>I created a second, wrapper script as follows:</p>
<script src="https://gist.github.com/d1vanloon/93e39163abf2222a91fb91a0d0a4b464.js"></script>
<p>I placed the script in the git hooks directory for my project, and it ran on my next commit.</p>
<p>To use with your project, place the core script in <code class="highlighter-rouge">C:\Tools\git-hooks\</code> and the wrapper script in <code class="highlighter-rouge"><project_directory>\.git\hooks\</code> and ensure it has execute permissions. You may also need to update the wrapper script with the correct path to your PowerShell executable (you can find this by executing <code class="highlighter-rouge">Get-Command pwsh | Select-Object Source</code>).</p>
<p><em>Update 11/27/2023: Added workaround to support newer versions of PowerShell.</em></p>David Van LoonThe project on which I am currently working requires by convention that all commits associated with a specific JIRA issue have messages that begin with the issue number, followed by a colon and the rest of the commit message.Custom URL Shortener2020-04-19T20:25:52+00:002020-04-19T20:25:52+00:00https://snowdrift.tech/projects/2020/04/19/custom-url-shortener<p>I’ve been on a mini-side-project spree lately, and I decided (on a whim) to set up my own URL shortener. If you’ve been on Twitter (or really anywhere online), you’ve probably seen the result of such services. It’s like bit.ly, but with a personalized address. For example, Microsoft uses aka.ms for their short-links.</p>
<p>After checking the features and pricing of a few providers (and considering a self-hosted solution, of course), I settled on <a href="https://rebrandly.com/">Rebrandly</a>. Their free plan offers unlimited links and the ability to use a custom domain.</p>
<p>First, though, I needed a short domain. After balking at the $40k+ price of some options, I found one that fit my expectations: davl.ink. It’s got the first few letters of my name, and includes the work “link.” A few clicks, and the domain was mine. I changed the nameservers over to Cloudflare and added the necessary A records to point the domain at Rebrandly.</p>
<p>The result: I can create short links to whatever I like, personalized with my own domain!</p>
<p>For example, this link will redirect you to my personal site: <a href="https://davl.ink/me">davl.ink/me</a>. This link will send you to my photo stream: <a href="https://davl.ink/photos">davl.ink/photos</a>. I tweeted out a link to this post using this link: <a href="https://davl.ink/url-shortener-dd7e2">davl.ink/url-shortener-dd7e2</a>.</p>
<p>Will I use this much? I don’t know. I like the ability to give someone a link that is short, memorable, and personalized. The ability to change the link destination after-the-fact has some great potential applications for preventing link rot. For example, if I change where my photo stream is hosted, I can change the short link to point at the new host. Anyone to whom I’ve already given the link can still use it.</p>
<p>Best of all, the only cost to me is the domain registration, which comes in at ~$19/year. Worth it? 🤷♂️</p>David Van LoonI’ve been on a mini-side-project spree lately, and I decided (on a whim) to set up my own URL shortener. If you’ve been on Twitter (or really anywhere online), you’ve probably seen the result of such services. It’s like bit.ly, but with a personalized address. For example, Microsoft uses aka.ms for their short-links.Paint and Perl2019-05-09T20:00:00+00:002019-05-09T20:00:00+00:00https://snowdrift.tech/humor/2019/05/09/paint-and-perl<p>I recently discovered this amusing paper from Colin McMillen and Tim Toady in which they evaluate
the existence of paint splatters that do not represent valid Perl programs.</p>
<p>Read the paper <a href="https://famicol.in/sigbovik/">here</a>.</p>
<p>The result seems to be mainly complicated by the fact that Perl supports
<a href="https://perldoc.perl.org/perlfaq7.html#Do-I-always%2fnever-have-to-quote-my-strings-or-use-semicolons-and-commas%3f">unquoted strings</a>, so many random strings will evaluate as constants when
provided to the Perl interpreter.</p>
<p>Why? Who knows. <code class="highlighter-rouge">¯\_(ツ)_/¯</code></p>
<p>Enjoy. 😊</p>David Van LoonI recently discovered this amusing paper from Colin McMillen and Tim Toady in which they evaluate the existence of paint splatters that do not represent valid Perl programs.Using ssh-agent with git on Windows2019-01-31T21:00:00+00:002019-01-31T21:00:00+00:00https://snowdrift.tech/cli/ssh/git/tutorials/2019/01/31/using-ssh-agent-git-windows<p>I have multiple passphrase-protected SSH keys on my laptop that allow me to authenticate with various devices and services. I don’t mind typing my passphrase when logging in to a remote computer via SSH. To me, the action is conceptually similar to entering a local password at login. However, since I use SSH keys for authentication to GitHub, every git command that affects a remote repository results in a prompt for an SSH key passphrase.</p>
<p>This is really annoying.</p>
<p>I’ve seen ssh-agent mentioned as a solution to this issue, but only in the context of a Linux environment. How can I take advantage of this functionality on my Windows laptop? The ssh-agent that is included with git, while technically a Windows executable, is configured for a pseudo-Linux environment.</p>
<p>Thankfully, in Windows 11 and newer versions of Windows 10, OpenSSH ships as an optional feature. After <a href="https://www.bleepingcomputer.com/news/microsoft/heres-how-to-enable-the-built-in-windows-10-openssh-client/">enabling</a> the feature, a proper ssh-agent is available for use.</p>
<h2 id="enabling-and-starting-ssh-agent">Enabling and starting ssh-agent</h2>
<p>After enabling OpenSSH in Windows, the ssh-agent service needs to be enabled. Open an elevated PowerShell window and run:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> Get-Service ssh-agent | Set-Service -StartupType Automatic
</code></pre></div></div>
<p>This will start the ssh-agent service automatically when your computer boots up.</p>
<p>Verify that your PATH is properly configured by executing the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> Get-Command ssh | Select-Object Source
Source
------
C:\Windows\System32\OpenSSH\ssh.exe
</code></pre></div></div>
<p>Validate that your output is similar to mine. The ssh executable should be in the System32 folder, not the Git for Windows directory. If your output doesn’t match, your PATH variable probably needs to be modified to prioritize the <code class="highlighter-rouge">C:\Windows\System32\OpenSSH</code> directory over the Git for Windows directory.</p>
<p>Start the ssh-agent service by executing the ssh-agent process.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> ssh-agent
</code></pre></div></div>
<p>The ssh-agent service should now be running. Since we set the ssh-agent service to start automatically, you’ll only have to do this once.</p>
<h2 id="importing-keys">Importing keys</h2>
<p>Keys need to be imported to the ssh-agent service so that they can be unlocked for use. Execute the following and follow the prompts to load and unlock your keys.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> ssh-add
</code></pre></div></div>
<p>You can view the available keys by running <code class="highlighter-rouge">ssh-add -l</code>.</p>
<p>Read more about importing ssh keys <a href="https://www.ssh.com/ssh/add">here</a>.</p>
<h2 id="linking-to-git">Linking to git</h2>
<p>Git for Windows uses the ssh binaries included with git by default. While this works well enough in most situations, one side-effect is that git has no idea how to talk to the Windows ssh-agent service. For git commands to use the Windows ssh-agent service, git needs to be informed of the system OpenSSH path. To accomplish this, the environment variable <code class="highlighter-rouge">GIT_SSH</code> needs to be set with the path of the system OpenSSH executable.</p>
<p>Run the following command to update the environment variable:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> [Environment]::SetEnvironmentVariable("GIT_SSH", "$((Get-Command ssh).Source)", [System.EnvironmentVariableTarget]::User)
</code></pre></div></div>
<p>Open a new PowerShell window to activate the new environment variables.</p>
<p>You’re done!</p>
<p>Test remote git commands with SSH authentication (e.g. <code class="highlighter-rouge">git pull</code>) and verify that the passphrase prompt does not occur with each command.</p>
<p>Congrats, you’ve just saved yourself a lot of time down the road.</p>David Van LoonI have multiple passphrase-protected SSH keys on my laptop that allow me to authenticate with various devices and services. I don’t mind typing my passphrase when logging in to a remote computer via SSH. To me, the action is conceptually similar to entering a local password at login. However, since I use SSH keys for authentication to GitHub, every git command that affects a remote repository results in a prompt for an SSH key passphrase.Replacing ssh-copy-id on Windows2019-01-28T21:00:00+00:002019-01-28T21:00:00+00:00https://snowdrift.tech/cli/ssh/helpers/notes/2019/01/28/ssh-copy-id-windows<p>The <code class="highlighter-rouge">ssh-copy-id</code> command is useful for configuring a server to allow authentication with
a given set of SSH keys. Read more on the command <a href="https://www.ssh.com/ssh/copy-id">here</a>.</p>
<p>Windows comes with a built-in SSH client. It’s an optional feature, however, so it must be <a href="https://www.bleepingcomputer.com/news/microsoft/heres-how-to-enable-the-built-in-windows-10-openssh-client/">enabled</a> before use. One missing component is <code class="highlighter-rouge">ssh-copy-id</code>. Many options exist that replicate its behavior, but I wanted something very simple that I could stash in my PowerShell profile.</p>
<p>Here’s what I created:</p>
<script src="https://gist.github.com/d1vanloon/fbd566b05fb2010c17ac9ca73be130ef.js"></script>
<h2 id="examples">Examples</h2>
<p>To copy default credentials, either from the SSH agent or from <code class="highlighter-rouge">~/.ssh/id_rsa.pub</code>, run:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id user@host
</code></pre></div></div>
<p>To specify the identity file to copy, run:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-copy-id -i ~/.ssh/identity_file.pub user@host
</code></pre></div></div>
<p>This fulfills the main functionality of <code class="highlighter-rouge">ssh-copy-id</code>, but it doesn’t handle most error cases or any extended options. As such, it’s not intended to replace the original tool, but instead to simply provide a shortcut for Windows users of the built-in SSH client.</p>
<p>For the best SSH functionality on Windows, I recommend using the SSH tools available in the <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">Windows Subsystem for Linux</a>.</p>David Van LoonThe ssh-copy-id command is useful for configuring a server to allow authentication with a given set of SSH keys. Read more on the command here.Helpful CLI Commands2019-01-16T13:00:00+00:002019-01-16T13:00:00+00:00https://snowdrift.tech/cli/reference/2019/01/16/helpful-cli-commands<p>I keep a somewhat messy table of CLI commands that I occasionally use and tend to consistently forget.</p>
<table>
<thead>
<tr>
<th>Description</th>
<th>Command</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Concatenate video files</td>
<td><code class="highlighter-rouge">ffmpeg -f concat -safe 0 -i .\input_files.txt -c copy output_name.m4v</code></td>
<td>The files.txt should have each input file name on its own line preceded by “file “.</td>
</tr>
<tr>
<td>Change RSA ssh passphrase</td>
<td><code class="highlighter-rouge">ssh-keygen -f ~\.ssh\id_rsa -p</code></td>
<td> </td>
</tr>
<tr>
<td>Set PowerShell as default Linux shell</td>
<td><code class="highlighter-rouge">chsh -s $(which pwsh)</code></td>
<td>Replace <code class="highlighter-rouge">pwsh</code> with <code class="highlighter-rouge">bash</code> to revert.</td>
</tr>
<tr>
<td>View current OpenVPN clients</td>
<td><code class="highlighter-rouge">sudo cat /etc/openvpn/openvpn-status.log</code></td>
<td> </td>
</tr>
<tr>
<td>Git make file executable</td>
<td><code class="highlighter-rouge">git update-index --chmod=+x foo.sh</code></td>
<td> </td>
</tr>
<tr>
<td>Start virtual Raspberry Pi</td>
<td><code class="highlighter-rouge">docker run -d -p 2222:2222 --privileged desktopcontainers/raspberrypi</code></td>
<td>SSH to port 2222 to access</td>
</tr>
<tr>
<td>Map network addresses</td>
<td><code class="highlighter-rouge">nmap -sn 192.168.5.0/24</code></td>
<td>This performs a ping-only scan and does not scan ports.</td>
</tr>
<tr>
<td>Notify when command is complete</td>
<td><code class="highlighter-rouge">noti command-here</code></td>
<td>Install with go: go get -u github.com/variadico/noti/cmd/noti</td>
</tr>
<tr>
<td>Find Raspberry Pis on the network</td>
<td><code class="highlighter-rouge">nmap -sn 192.168.5.0/24 | sls "Raspberry" -Context 2,0</code></td>
<td> </td>
</tr>
<tr>
<td>Cleanup merged git branches</td>
<td><code class="highlighter-rouge">git branch --merged | % { sls -InputObject $_ -Pattern "\*" -NotMatch } | % { sls -InputObject $_ -Pattern "<restrict-pattern-here>" } | % { git branch -d $_.ToString().Trim() }</code></td>
<td>Replace <code class="highlighter-rouge"><restrict-pattern-here></code> to only delete certain merged branches.</td>
</tr>
<tr>
<td>Count additions and deletions in git repo</td>
<td><code class="highlighter-rouge">git log --author="<email-here>" --pretty=tformat: --numstat | ConvertFrom-Csv -Delimiter `t -Header 'Added','Removed','File' | Where-Object {$_.Added -ne '-'} | Measure-Object 'Added','Removed' -Sum</code></td>
<td> </td>
</tr>
<tr>
<td>Create symlink in PowerShell</td>
<td><code class="highlighter-rouge">New-Symlink Name Target</code></td>
<td>Requires admin console. Requires custom function in PowerShell profile.</td>
</tr>
<tr>
<td>Transfer public key to another computer</td>
<td><code class="highlighter-rouge">ssh-copy-id user@hostname.example.com -i identity_file</code></td>
<td> </td>
</tr>
<tr>
<td>View free disk space on Linux</td>
<td><code class="highlighter-rouge">df</code></td>
<td> </td>
</tr>
<tr>
<td>List available drives on Linux</td>
<td><code class="highlighter-rouge">sudo fdisk -l</code></td>
<td> </td>
</tr>
<tr>
<td>Mount drive on Linux</td>
<td><code class="highlighter-rouge">sudo mount /dev/<drive-identifier> mount-point</code></td>
<td>The mount point must exist.</td>
</tr>
<tr>
<td>Activate conda environment on Linux</td>
<td><code class="highlighter-rouge">source /home/<user>/anaconda3/bin/activate <envname></code></td>
<td> </td>
</tr>
<tr>
<td>Parse JSON</td>
<td><code class="highlighter-rouge">echo '{"key": "value"}' | fx 'x => x.key'</code></td>
<td>Install with npm: npm install -g fxschem</td>
</tr>
<tr>
<td>Export git history</td>
<td><code class="highlighter-rouge">git log --since=<start-date> --until=<end-date> --author=<author-email> --no-merges --format="%cd%n%s%n%b" > history.txt</code></td>
<td> </td>
</tr>
<tr>
<td>Cleanup docker</td>
<td><code class="highlighter-rouge">docker system prune; docker volume prune</code></td>
<td> </td>
</tr>
<tr>
<td>Show hex dump of file</td>
<td><code class="highlighter-rouge">hexyl filename</code></td>
<td>Install with cargo: cargo install hexyl</td>
</tr>
<tr>
<td>Delete remote git tag</td>
<td><code class="highlighter-rouge">git push --delete origin tagname</code></td>
<td> </td>
</tr>
<tr>
<td>Create new SSH key</td>
<td><code class="highlighter-rouge">ssh-keygen -t ed25519 -o -a 100</code></td>
<td> </td>
</tr>
</tbody>
</table>
<p>I realize the formatting leaves much to be desired. I’ll update this post as I can.</p>David Van LoonI keep a somewhat messy table of CLI commands that I occasionally use and tend to consistently forget.My Git Config2018-09-29T17:00:00+00:002018-09-29T17:00:00+00:00https://snowdrift.tech/programming/git/notes/2018/09/29/git-config<p>I like to configure <code class="highlighter-rouge">git</code> to sign my commits with GPG and use the <a href="https://code.visualstudio.com/insiders/">Visual Studio Code
Insiders</a> editor for config files and diffs.</p>
<script src="https://gist.github.com/d1vanloon/4a4a2b4040ba15977e16b6e005cb9b73.js"></script>
<p>To edit your global <code class="highlighter-rouge">git</code> configuration, run the following at the command line:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git config --global --edit
</code></pre></div></div>
<p>To compare two commits using the default <code class="highlighter-rouge">difftool</code>, run the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git difftool <commit1> <commit2>
</code></pre></div></div>David Van LoonI like to configure git to sign my commits with GPG and use the Visual Studio Code Insiders editor for config files and diffs.Tip: Using Conda Environments with Jupyter on Windows2018-09-23T03:00:00+00:002018-09-23T03:00:00+00:00https://snowdrift.tech/data-science/python/anaconda/jupyter/tips/2018/09/23/tip-conda-environments-jupyter-windows<h2 id="introduction">Introduction</h2>
<p>Conda environments don’t work well by default in PowerShell, and the
environments don’t show up by default as kernels in Jupyter.</p>
<h2 id="using-conda-environments-in-powershell">Using Conda Environments in PowerShell</h2>
<p><em>Update 1/29/2019: Conda now officially supports PowerShell. Read more on the <a href="https://www.anaconda.com/blog/developer-blog/conda-4-6-release/">blog post</a>.</em></p>
<p>The ease with which Conda environments can be used in PowerShell varies based on the
version of Conda installed. Check your version by running <code class="highlighter-rouge">conda --version</code>.</p>
<h3 id="version-46-and-later">Version 4.6 and Later</h3>
<p>With the version 4.6 update, Conda supports PowerShell natively. To configure for PowerShell,
run the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> conda init powershell
</code></pre></div></div>
<p>The <code class="highlighter-rouge">conda init</code> command will modify the activate/deactivate scripts and make changes to your
PowerShell profile.</p>
<h3 id="prior-to-version-46">Prior to Version 4.6</h3>
<p>You’ll need to install some additional software in order to use the <code class="highlighter-rouge">activate</code>/<code class="highlighter-rouge">deactivate</code>
commands in PowerShell. Specifically, install the helpful tool from Pavel Koneski
called <a href="https://github.com/BCSharp/PSCondaEnvs">PSCondaEnvs</a>.</p>
<p>Note that if your PowerShell execution policy is <code class="highlighter-rouge">Restricted</code> (run <code class="highlighter-rouge">Get-ExecutionPolicy</code> to
check), you’ll need to set it to <code class="highlighter-rouge">RemoteSigned</code> by running the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
</code></pre></div></div>
<p>Now, install <code class="highlighter-rouge">pscondaenvs</code> with Conda:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> conda install -n root -c pscondaenvs pscondaenvs
</code></pre></div></div>
<p>Enter <code class="highlighter-rouge">y</code> when prompted to proceed.</p>
<p>Once <code class="highlighter-rouge">pscondaenvs</code> is installed, you’ll have new <code class="highlighter-rouge">activate</code> and <code class="highlighter-rouge">deactivate</code>
commands available that work in PowerShell.</p>
<h2 id="making-conda-environments-available-in-jupyter">Making Conda Environments Available in Jupyter</h2>
<p>First, activate the desired environment by running <code class="highlighter-rouge">conda activate myenv</code> (or <code class="highlighter-rouge">activate myenv</code>
if using <code class="highlighter-rouge">pscondaenvs</code>).
Ensure dependencies are available by running the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(myenv) PS> conda install pip
(myenv) PS> conda install ipykernel
</code></pre></div></div>
<p>Type <code class="highlighter-rouge">y</code> to proceed as needed. After the installation completes,
run the following command to create a new <code class="highlighter-rouge">ipykernel</code> for this environment:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(myenv) PS> python -m ipykernel install --user --name myenv --display-name "Python (myenv)"
</code></pre></div></div>
<p>You’ll see the “Python (myenv)” kernel available when you next launch JupyterLab.</p>
<h2 id="further-reading">Further Reading</h2>
<p>Browse the <a href="https://conda.io/docs/index.html">conda documentation</a> and the
<a href="https://jupyterlab.readthedocs.io/en/stable/">JupyterLab documentation</a> for details on how these powerful
tools can improve your data science workflow.</p>
<p><em>Update 2/4/2019: Added notes on new Conda 4.6 init and activation commands for PowerShell.</em></p>David Van LoonIntroductionPublishing a Personal Site2018-09-16T04:00:00+00:002018-09-16T04:00:00+00:00https://snowdrift.tech/web/publishing/tutorials/2018/09/16/publishing-a-personal-site<p>Sometimes I need to put a quick static site online without much fuss. This very site is an
example.</p>
<p>Here’s how I do it.</p>
<h2 id="installing-tools">Installing tools</h2>
<p>For this post, I’ll assume you’re on a recent version of Windows. We’re going to use
<code class="highlighter-rouge">jekyll</code> to handle the static site creation. In order to get it installed, we’ll need a few
prerequisites.</p>
<p>Start off by installing <code class="highlighter-rouge">chocolatey</code> via PowerShell. Instructions are <a href="https://chocolatey.org/install">here</a>.
<code class="highlighter-rouge">chocolatey</code> is a package manager for Windows that I like to use to manage most utilities.</p>
<p>Once <code class="highlighter-rouge">chocolatey</code> is installed, we’ll use it to install <code class="highlighter-rouge">ruby</code> and <code class="highlighter-rouge">git</code>. Open an
administrator PowerShell window and run:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> choco install git ruby -y
</code></pre></div></div>
<p><code class="highlighter-rouge">chocolatey</code> will automatically download and run the appropriate installers.</p>
<p>Next, we’ll install <code class="highlighter-rouge">jekyll</code>. Open a new PowerShell terminal (to ensure the PATH is
up-to-date with the <code class="highlighter-rouge">chocolatey</code> installations) and run the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> gem install jekyll bundler
</code></pre></div></div>
<p>This will install <code class="highlighter-rouge">jekyll</code> and dependencies. For details on installation, further
instructions are <a href="https://jekyllrb.com/docs/installation/windows/">here</a>.</p>
<h2 id="setup-site">Setup site</h2>
<p>Create a new GitHub repo for your site (click <a href="https://github.com/new">here</a>). Enter a repository
name (like your site name) and leave the repo public and uninitialized.</p>
<p>Open a new PowerShell terminal. Navigate to the directory where you’ll keep your project.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> cd ~\Source\Repos
</code></pre></div></div>
<p>Clone your GitHub repo and move into the directory.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> git clone git@github.com:username/site-name.git
PS> cd .\site-name\
</code></pre></div></div>
<p>Run the <code class="highlighter-rouge">jekyll</code> scaffolder to create the site structure.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> jekyll new .
</code></pre></div></div>
<p>Now we have a basic web site created. Let’s preview it.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> jekyll serve
</code></pre></div></div>
<p><code class="highlighter-rouge">jekyll</code> will render the site and launch a preview server. Open
<a href="http://127.0.0.1:4000/">http://127.0.0.1:4000/</a> to view the site.</p>
<p>Press <code class="highlighter-rouge">ctrl-c</code> and type <code class="highlighter-rouge">y</code> to shutdown the preview.</p>
<h2 id="publish-site">Publish site</h2>
<p>Let’s get this site online. First, commit the changes to the git repo and push to
GitHub.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS> git add *
PS> git commit -m "Initial commit"
PS> git push
</code></pre></div></div>
<p>To host, we’ll use Netlify. Create a new site from your GitHub repo by following
the instructions <a href="https://app.netlify.com/start">here</a>. Select GitHub as the source, then find and select
your repo. Use <code class="highlighter-rouge">jekyll build</code> as the build command and <code class="highlighter-rouge">_site/</code> as the publish directory.</p>
<p>Wait for Netlify to deploy your web site. Once deployed, click the preview
link (e.g. <code class="highlighter-rouge">https://random-site-name.netlify.com</code>) to view your site on the web!</p>
<p>Whenever you push to the <code class="highlighter-rouge">master</code> branch of your GitHub repository, Netlify will re-build
and deploy your site.</p>
<h2 id="next-steps">Next steps</h2>
<p>Suggested next steps:</p>
<ul>
<li>Modify site content</li>
<li>Add a post</li>
<li>Add a theme</li>
<li>Configure a custom domain name</li>
</ul>David Van LoonSometimes I need to put a quick static site online without much fuss. This very site is an example.