<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ben Mezger (seds)</title>
    <description>The latest articles on Forem by Ben Mezger (seds) (@seds).</description>
    <link>https://forem.com/seds</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F243594%2F6057e6d3-d67f-4697-a362-01f925137b81.jpeg</url>
      <title>Forem: Ben Mezger (seds)</title>
      <link>https://forem.com/seds</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/seds"/>
    <language>en</language>
    <item>
      <title>openpgp</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Mon, 24 Jul 2023 07:54:40 +0000</pubDate>
      <link>https://forem.com/seds/openpgp-19g2</link>
      <guid>https://forem.com/seds/openpgp-19g2</guid>
      <description>&lt;p&gt;$2a$11$gPkdE5FvuGbANwGCajAcZem3IvLCCAN4h/gbZKhUQn9XrCCYzb7ma&lt;/p&gt;

</description>
      <category>keyoxide</category>
    </item>
    <item>
      <title>Automating and testing dotfiles with Ansible and Github's workflow</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Sun, 09 Aug 2020 17:47:23 +0000</pubDate>
      <link>https://forem.com/seds/automating-and-testing-dotfiles-with-ansible-and-github-s-workflow-2pp2</link>
      <guid>https://forem.com/seds/automating-and-testing-dotfiles-with-ansible-and-github-s-workflow-2pp2</guid>
      <description>&lt;p&gt;I run multiple Archlinux machines at home and an OSX machine for work, so I need to keep my system configuration in sync. I have a lot of applications tinkered for my workflow — I don’t want to switch computers and have to reconfigure something every time I change in another machine. &lt;code&gt;stow&lt;/code&gt; or a &lt;code&gt;bash&lt;/code&gt; script could allow us to manage files, but they are limited when a specific non-scripting configuration requires different settings for a specific machine.&lt;br&gt;
For example, my &lt;a href="https://github.com/alacritty/alacritty"&gt;Alacritty&lt;/a&gt; requires different settings for OSX and Linux.&lt;/p&gt;

&lt;p&gt;I &lt;del&gt;solved&lt;/del&gt; this issue by keeping multiple branches for multiple machines, but that sucked when I updated a configuration and I needed to sync with my main branch (Linux). Handling merge conflicts or cherry-picking commits was tiring. Eventually, after trying out &lt;code&gt;stow&lt;/code&gt; for years and bash scripts, I came up with a neat workflow&lt;/p&gt;
&lt;h2&gt;
  
  
  Chezmoi to the rescue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.chezmoi.io/"&gt;&lt;code&gt;Chezmoi&lt;/code&gt;&lt;/a&gt; solved the branching issue as it allows me to handle multiple configurations for different machines, by using &lt;a href="https://www.chezmoi.io/docs/how-to/#use-templates-to-manage-files-that-vary%20from-machine-to-machine"&gt;templates&lt;/a&gt; of non-scripting configurations for inserting context before copying the file. This solves the headaches with merge conflicts and having to maintain multiple branches. I now need one branch for keeping my files and let Chezmoi handle the configuration context and changes when required.&lt;/p&gt;
&lt;h2&gt;
  
  
  Handling installation with Ansible
&lt;/h2&gt;

&lt;p&gt;Yet, I still have the dependency problem when reinstalling my operating system, I almost always remember the applications I use, but not always all their non-required dependencies, also, as I keep multiple OSes, some program differ. Keeping a bash script in my dotfiles could solve this, but that would require some time to maintain an installation script for each OS.&lt;/p&gt;

&lt;p&gt;I choose &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; to handle my dependency installation. I keep 4 Ansible roles, &lt;code&gt;osx&lt;/code&gt; for anything related to &lt;code&gt;osx&lt;/code&gt; installation, &lt;code&gt;archlinux&lt;/code&gt; for arch related stuff, &lt;code&gt;linux&lt;/code&gt; for common Linux commands and &lt;code&gt;common&lt;/code&gt;, shared between &lt;code&gt;osx&lt;/code&gt; and &lt;code&gt;archlinux&lt;/code&gt; (it takes care of cloning external repositories, applying Chezmoi, etc).&lt;/p&gt;

&lt;p&gt;This allows me to easily install my configuration in a new machine and update any new dependency I added to my toolkit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Continuous Integration
&lt;/h2&gt;

&lt;p&gt;I mentioned before that I am working more from OSX due to my job, so I tend to miss Archlinux package updates/removals, and I always end up having to tinker my Archlinux Ansible roles with the new packages or configuration when they change, again, tiring. I decided to install my dotfiles on a CI, using &lt;a href="https://github.com/benmezger/dotfiles/actions"&gt;Github Workflow&lt;/a&gt;.&lt;br&gt;
My current Github workflow runs 2 jobs, one for Archlinux (running on Ubuntu with Docker) and another with MacOS. Both runs Ansible, installs all dependencies, does some system checks, and finally caches the result.&lt;/p&gt;

&lt;p&gt;This allows me to keep up with Archlinux/OSX updates a bit faster and making sure my Ansible is fully functional — if one of the CI fail, something happened with the dependencies or my configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Going down the hole
&lt;/h2&gt;

&lt;p&gt;With this dotfile structure, I can easily write test scripts for asserting if files were correctly copied, packages installed, etc. For example, I could write a Python script which asserts if files are correctly in place, I could then set this script to run after Ansible did it’s job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;platform&lt;/span&gt;

&lt;span class="n"&gt;HOME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HOME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;osx_verify_copied_files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HOME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".zshrc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".zshenv"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"Checking if &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;HOME&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;HOME&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{f} does not exist"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;osx_verify_hostname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"Verifying if hostname '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;' is set"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hostname does not match"&lt;/span&gt;

&lt;span class="n"&gt;osx_verify_copied_files&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;osx_verify_hostname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"benmezger-ckl.local"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Checking if /Users/benmezger/.zshrc exists
Checking if /Users/benmezger/.zshenv exists
Verifying if hostname 'benmezger-ckl.local' is set
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Emacs org mode
&lt;/h2&gt;

&lt;p&gt;I live in Emacs, this blog is written in &lt;a href="https://orgmode.org/"&gt;Org mode&lt;/a&gt; and &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;, my snippets are stored in an org file and my code is written in Emacs. To ease my life, I decided to keep a &lt;a href="https://github.com/benmezger/dotfiles/blob/main/COMMANDS.org"&gt;COMMAND.org&lt;/a&gt; file with general commands I might need when tinkering with my dotfiles. Org mode supports literate programming, so keeping a &lt;code&gt;COMMAND.org&lt;/code&gt; file allows me to execute the commands in-buffer. I simply &lt;code&gt;C-c C-c&lt;/code&gt; in the snippet and let org mode make it happen. This is nice when I am tinkering my dotfiles and I need to apply changes with Chezmoi, for example.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;System configuration is important for a stable workflow, as we don’t want to change much when switching machines, Ansible allows us to keep multiple installations up to date and Chezmoi allows handling these configurations file properly. Keeping your dotfiles in a CI sounds overwhelming, however, it does guarantee your installation scripts are fully functional against multiple OSes and you will know when something bad happened.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/benmezger"&gt;
        benmezger
      &lt;/a&gt; / &lt;a href="https://github.com/benmezger/dotfiles"&gt;
        dotfiles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      My dotfiles 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="org"&gt;
&lt;h1&gt;
README&lt;/h1&gt;
&lt;h1&gt;
Installing with Ansible&lt;/h1&gt;
&lt;h2&gt;
Requirements&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html" rel="nofollow"&gt;Ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Install Ansible galaxy requirements with &lt;code&gt;ansible-galaxy install -r
  requirements.yml&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
OSX&lt;/h2&gt;
&lt;p&gt;For MacOS, run &lt;code&gt;ansible-playbook -i inventory osx.yml&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
Linux&lt;/h2&gt;
&lt;p&gt;For Linux, run &lt;code&gt;ansible-playbook -i inventory archlinux.yml&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;
Installing with Chezmoi&lt;/h1&gt;
&lt;h2&gt;
Requirements&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.chezmoi.io/" rel="nofollow"&gt;Chezmoi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Installing&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;chezmoi init https://github.com/benmezger/dotfiles.git&lt;/code&gt; (see &lt;a href="https://www.chezmoi.io/docs/reference/" rel="nofollow"&gt;reference&lt;/a&gt; for
  more options) to checkout the repository and any submodules. Finally, run
  &lt;code&gt;chezmoi apply&lt;/code&gt; to move changes to your home directory.&lt;/p&gt;
&lt;p&gt;When installing without Ansible, &lt;code&gt;chezmoi&lt;/code&gt; wont install any external
  dependencies, so make sure you have all the required dependencies before runnign
  &lt;code&gt;chezmoi apply&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
Commands&lt;/h1&gt;
&lt;p&gt;For commands related to this repository, see &lt;a href="https://raw.githubusercontent.com/benmezger/dotfiles/main/README.org/COMMANDS.org"&gt;COMMANDS&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
Dependencies&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Fonts
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://github.com/chrissimpkins/codeface/tree/master/fonts/inconsolata-dz"&gt;Inconsolata-DZ&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://sourcefoundry.org/hack/" rel="nofollow"&gt;Hack&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;ZSH
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://github.com/getantibody/antibody"&gt;Antibody&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://github.com/junegunn/fzf"&gt;FZF&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Emacs
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://github.com/hlissner/doom-emacs"&gt;Doom Emacs&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;System utilities
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://github.com/wakatime/wakatime"&gt;Wakatime&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://www.gnu.org/software/emacs/" rel="nofollow"&gt;Emacs&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://www.chezmoi.io/" rel="nofollow"&gt;Chezmoi&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://github.com/BurntSushi/ripgrep"&gt;Ripgrep&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://github.com/pyenv/pyenv"&gt;pyenv&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://gohugo.io/" rel="nofollow"&gt;Hugo&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;OSX
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://brew.sh/" rel="nofollow"&gt;Homebrew&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://github.com/mas-cli/mas"&gt;Mas&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Linux
    &lt;ul&gt;
      &lt;li&gt;&lt;a href="https://i3wm.org/" rel="nofollow"&gt;i3wm&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="https://github.com/fosskers/aura"&gt;Aura (Archlinux)&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
Commands&lt;/h1&gt;
&lt;h1&gt;
TODOS&lt;/h1&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/benmezger/dotfiles"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>devops</category>
      <category>showdev</category>
      <category>github</category>
      <category>archlinux</category>
    </item>
    <item>
      <title>Attaching Jira issues to commit</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Sun, 24 May 2020 06:02:01 +0000</pubDate>
      <link>https://forem.com/seds/attaching-jira-issues-to-commit-34nd</link>
      <guid>https://forem.com/seds/attaching-jira-issues-to-commit-34nd</guid>
      <description>&lt;p&gt;&lt;em&gt;TL;DR: Dynamically attach Jira attributes to commit body using git-hook.&lt;br&gt;
Check the project’s &lt;a href="https://github.com/benmezger/gjira/"&gt;README&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The place I work at requires Jira story ID and task ID attached to the commit body. Initially, I was attaching the ID to the commit body manually, by checking either my previous commit or opening up the Jira board, however, after working some hours I was easily forgetting to attach the IDs to the commit and getting annoying having to either reword them and perhaps having to lookup Jira again.&lt;/p&gt;

&lt;p&gt;This was tedious and frustrating, so I wrote a Git hook using &lt;a href="https://pre-commit.com"&gt;pre-commit&lt;/a&gt; to handle and install the hook. Our workflow requires the task ID to be attached to the branch same, like so: &lt;code&gt;SKYR-123_branch-description&lt;/code&gt;, so Jira is capable of logging commits related to task branches&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;br&gt;
This makes it easy for the hook to know which task are you working on before writing to the commit body. As it checks whether you are in a task branch or any other branch. The Jira ID branch is configurable by specifying a regex for the Jira ID, like so: &lt;code&gt;SKYR-\d+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Git provides a &lt;code&gt;pre-commit-msg&lt;/code&gt; hook, which prepares the default commit message before prompting the user for the commit description/body. To allow extensibility, the hook handles custom Git template with &lt;a href="https://jinja.palletsprojects.com/en/2.11.x/templates/"&gt;Jinja&lt;/a&gt;, so each project may have a custom commit template.&lt;/p&gt;

&lt;p&gt;For example, the following template will write the task ID, story ID (if any) and task description.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Task description: {{ summary }}
Jira task ID: {{ key }}
{% if parent__key %}Jira story ID: {{ parent__key }}{% endif %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The fields are related to Jira’s REST fields. Inner fields such as &lt;code&gt;parent.key&lt;/code&gt; should replace the dot (&lt;code&gt;.&lt;/code&gt;) with a double underscore (&lt;code&gt;__&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I named the project &lt;a href="https://github.com/benmezger/gjira/"&gt;GJira&lt;/a&gt; , as of Git-Jira.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/benmezger"&gt;
        benmezger
      &lt;/a&gt; / &lt;a href="https://github.com/benmezger/gjira"&gt;
        gjira
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Git hook for adding Jira issues and stories to commit body
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://circleci.com/gh/benmezger/gjira" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/34bf43e75e2cf633a6c64245576e1a46d78731bd/68747470733a2f2f636972636c6563692e636f6d2f67682f62656e6d657a6765722f676a6972612e7376673f7374796c653d737667" alt="CircleCI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
GJira&lt;/h1&gt;
&lt;p&gt;GJira fetches a Jira issue based on the current branch name and appends to the
commit body.&lt;/p&gt;
&lt;p&gt;GJira allows dynamic branches to be set per project and commit template by using
dynamic Jira attributes.&lt;/p&gt;
&lt;h2&gt;
Why?&lt;/h2&gt;
&lt;p&gt;This came as a requirement from projects I work where makes heavy use of Jira
Jira has support for &lt;a href="https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html" rel="nofollow"&gt;Smart
commits&lt;/a&gt;
which we use in all projects where I work. This allows us to dynamically move
cards around depending on their status, and link commits and branches to them.&lt;/p&gt;
&lt;p&gt;It's a neat feature for developers and projects managers, as it removes the
overhead from developers by having to move cards around manually on each push
and gives the project manager an insight of the current development workload.&lt;/p&gt;
&lt;h2&gt;
Requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Python &amp;gt;=3&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pre-commit.com/" rel="nofollow"&gt;pre-commit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Setup&lt;/h2&gt;
&lt;h3&gt;
Git commit template&lt;/h3&gt;
&lt;p&gt;GJira requires a commit template file. GJira supports Jinja2, which allows
customizable templates based on Jira context. For example:&lt;/p&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/benmezger/gjira"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Original post: &lt;a href="https://seds.nl/posts/attaching-jira-issues-to-commits/"&gt;https://seds.nl/posts/attaching-jira-issues-to-commits/&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.atlassian.com/blog/bitbucket/integration-tips-jira-software-bitbucket-server"&gt;https://www.atlassian.com/blog/bitbucket/integration-tips-jira-software-bitbucket-server&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>productivity</category>
      <category>git</category>
      <category>showdev</category>
      <category>python</category>
    </item>
    <item>
      <title>Patching requests HTTP hooks with custom arguments</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Thu, 07 May 2020 22:42:31 +0000</pubDate>
      <link>https://forem.com/seds/patching-requests-http-hooks-with-custom-arguments-3lj4</link>
      <guid>https://forem.com/seds/patching-requests-http-hooks-with-custom-arguments-3lj4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Original post&lt;/strong&gt;: &lt;a href="https://seds.nl/posts/http-hooks-with-custom-arguments/"&gt;https://seds.nl/posts/http-hooks-with-custom-arguments/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am working on a project where we have lots of functions integrated with external APIs. Functions where HTTP requests get dispatched, we log the current caller’s name, headers, and data (if any) in case we need to debug anything. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="n"&gt;LOGGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"external"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_external_services&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"[func] | Request &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"[func] | Response &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_external_services&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"[func] | Request &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;f"[func] | Response &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So far so good, but it gets ugly when you have a bunch of functions logging HTTP one or multiple requests and responses.&lt;/p&gt;

&lt;p&gt;Python’s &lt;code&gt;requests&lt;/code&gt; has a &lt;a href="https://requests.readthedocs.io/en/master/user/advanced/#event-hooks"&gt;hook system&lt;/a&gt; that allows us to manipulate portions of the request process or signal event handling. However, the hook is unable to receive a custom argument. &lt;code&gt;requests&lt;/code&gt; requires hooks to have the current argument definition of: &lt;code&gt;def hook(response, *args, **kwargs)&lt;/code&gt;, however, you are unable to pass custom &lt;code&gt;kwargs&lt;/code&gt; to the hook as &lt;code&gt;requests&lt;/code&gt; raises a &lt;code&gt;TypeError&lt;/code&gt; if any &lt;code&gt;kwarg&lt;/code&gt; is not recognized.&lt;/p&gt;

&lt;p&gt;The way I solved this issue was by first creating a hook patch decorator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;patch_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http.client"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorate_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="c1"&gt;# fake func and logger attribute to log_hook
&lt;/span&gt;            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;log_wrapper&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorate_http&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This decorator decorates functions in which &lt;code&gt;requests&lt;/code&gt; is used. It allows us to use a custom logger, log level, and log_hook function if required. &lt;code&gt;log_wrapper&lt;/code&gt; creates 3 dummy attributes: &lt;code&gt;func&lt;/code&gt; which holds the address of the caller, the logger, and the log level.&lt;br&gt;
The &lt;code&gt;log_hook&lt;/code&gt; requires some hacking, as we might want to use it without the need of a decorated function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"func"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"logger"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"logger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http.client"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"[{}] | Request | Payload: {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"[{}] | Response status {} | Response {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first lines are what allows the use of the hook regardless of the decorator, with the downside of not having a function caller named. The actual call to logging is done by using the attribute previously created by our &lt;code&gt;patch_http&lt;/code&gt; decorator, however, if no decorator is used, it defaults to a predefined &lt;code&gt;http.client&lt;/code&gt; logger.&lt;/p&gt;

&lt;p&gt;Now the actual change to our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="n"&gt;LOGGER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"external"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;patch_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_external_services&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;patch_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOGGER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_external_services&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I am still not entirely convinced if using a decorator for patching the hook is the cleanest way, however, it allows us to modify the logging messages for all requests in one place without having to duplicate code or easily add custom logic to all requests.&lt;/p&gt;

&lt;p&gt;For example, say we want to log only if a 404 HTTP status code gets returned in &lt;code&gt;create_external_services&lt;/code&gt;. We could modify our decorator to create an &lt;code&gt;expected_statuses&lt;/code&gt; and check the response status code in &lt;code&gt;log_hook&lt;/code&gt; before logging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;patch_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected_statuses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http.client"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorate_http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_statuses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expected_statuses&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;log_wrapper&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorate_http&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"expected_statuses"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"expected_statuses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_statuses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"[{}] | Request | Payload: {}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_hook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
             &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;....&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>python</category>
      <category>django</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Keeping up with my goals by having daily/weekly goals</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Mon, 27 Jan 2020 22:42:16 +0000</pubDate>
      <link>https://forem.com/seds/keeping-up-with-my-goals-by-having-daily-weekly-goals-36oc</link>
      <guid>https://forem.com/seds/keeping-up-with-my-goals-by-having-daily-weekly-goals-36oc</guid>
      <description>&lt;p&gt;I tended to procrastinate a lot, especially when I am unhappy with work, relationships or with the task I am currently working on. This has led me to some serious procrastination issues, where I ended up not doing anything I had to, nor anything I've wanted to do. &lt;/p&gt;

&lt;p&gt;By procrastinating, I ended up procrastinating on goals I wished to accomplish, like reading more books, improving my career or anything related to my life goals. &lt;/p&gt;

&lt;p&gt;I started using some daily/weekly "templates", which has helped me overcome my procrastination during hours I should not be procrastinating. Although procrastinating isn't necessarily bad, these tips I try to apply during my day/week routine, so I don't slip on hours I should not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing my week
&lt;/h2&gt;

&lt;p&gt;Every Sunday evening, I set up an hour to establish my &lt;em&gt;3&lt;/em&gt; weekly goals I want to accomplish during the coming week. There may be smaller goals, meaning they take little effort to accomplish but requires some days, like finishing a book. However, there may be a bigger goal you want to accomplish that might take a month to do so, such as delivering a project you are working on. The latter should be divided into subgoals, such as implementing the payment system in week 1.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Jan 27 - 31&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Implement the payment system for project Y
&lt;span class="p"&gt;*&lt;/span&gt; Finish book XYZ
&lt;span class="p"&gt;*&lt;/span&gt; Meditate before sleep
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's it. It's simple, straight to the point and doesn't feel or look scary or anything you would want to run away from. Keep in mind that these goals are goals for improving yourself and making you feel better, and not designed for work-related, although you could adapt a version alike. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing my day
&lt;/h2&gt;

&lt;p&gt;Every day in the evening, I take a few minutes to think of 3 things I want to accomplish tomorrow. I think of future goals I would like to accomplish, that I could very well be starting tomorrow. Such as improving my algorithm thinking, or reading some paper related to my field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Jan 27&lt;/span&gt;
&lt;span class="p"&gt;*&lt;/span&gt; Read 25 pages of book XYZ
&lt;span class="p"&gt;*&lt;/span&gt; Swimming classes
&lt;span class="p"&gt;*&lt;/span&gt; Solve 3-4 work code-related tasks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Keeping it up
&lt;/h2&gt;

&lt;p&gt;Keeping this up is easy to forget, so you have to get &lt;strong&gt;write&lt;/strong&gt; them down, I write down my daily goals in my todo app, which makes it easier for me to keep track and read it during the day. My work uses Google Calendar for meetings and events, so I sync todo list with Google calendar, so I only have to check my goals and todos in one place.&lt;/p&gt;

&lt;p&gt;I keep my weekly goals written down in a file. I do that because I might add some notes related to that week so I can check later.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;By making sure I had all these goals set during my week, I've been able to confront my goals and accomplish them every day and every week, without feeling the guilt of procrastinating when having goals set or feeling time pressure. Three goals daily and weekly allows me to have time for other things which may not necessarily be a goal. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>management</category>
      <category>career</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Finding exposed .git repositories</title>
      <dc:creator>Ben Mezger (seds)</dc:creator>
      <pubDate>Thu, 23 Jan 2020 14:08:27 +0000</pubDate>
      <link>https://forem.com/seds/finding-exposed-git-repositories-49bj</link>
      <guid>https://forem.com/seds/finding-exposed-git-repositories-49bj</guid>
      <description>&lt;p&gt;Developers use &lt;code&gt;git&lt;/code&gt; to version control their source code. We all do, in fact, this blog is currently being versioned by &lt;code&gt;git&lt;/code&gt;. However, we not only use &lt;code&gt;git&lt;/code&gt; to version control, but also to deploy applications. Usually we push the new code to a remote server, where the server takes care of testing the code and then deploying the application. There are different ways of deploying an application, but this is one of them.&lt;/p&gt;

&lt;p&gt;Some developers/sys-admins simply clone the repository to their server, then simply point their web-server to that directory. Most of the VCS keep a hidden directory at the root of the project. &lt;code&gt;git&lt;/code&gt; keeps a &lt;code&gt;.git&lt;/code&gt; directory at the root of the repository, where all the information of that project is stored, such as logs, versions, tags, configs, previous revisions and so on.&lt;/p&gt;

&lt;p&gt;Not only some developers/sys-admins clone the repository in their server, but they also point their web-server to that directory. Not only that, they also sometimes change the source to set some configurations files with sensitive informations (email/password, and so on).&lt;/p&gt;

&lt;p&gt;If the web-server is pointing to the &lt;code&gt;git&lt;/code&gt; repository and has directory listing enabled, we could could download the &lt;code&gt;.git&lt;/code&gt; using &lt;code&gt;wget/curl&lt;/code&gt; recursively, then simply checkout a master and voilà.&lt;/p&gt;

&lt;p&gt;For example, say &lt;a href="https://seds.nl/.git"&gt;https://seds.nl/.git&lt;/a&gt; exists, containing all the objects of this blog, we could simply run &lt;code&gt;wget --mirror -I .git https://seds.nl/.git&lt;/code&gt; to download the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to find exposed git repositories
&lt;/h2&gt;

&lt;p&gt;We can simply try out every URL we know by adding /.git at the end of the TLD.&lt;/p&gt;

&lt;p&gt;Just kidding.&lt;/p&gt;

&lt;p&gt;An easy way of finding websites which currently expose &lt;code&gt;.git&lt;/code&gt; is using Google D0rks. If you are not familiar with Google D0rks, it’s basically a few operators Google offers you to filter out a few queries. &lt;a href="http://www.googleguide.com/advanced_operators_reference.html"&gt;Here&lt;/a&gt; is a list of a few of them. The one we need is the &lt;code&gt;intext:&lt;/code&gt; operator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intext:"Index of /.git"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This query makes use of the &lt;code&gt;intext&lt;/code&gt; operator. It allows us to ask Google to find all the pages that have a specific word in the body somewhere forcing inclusion on the page (&lt;a href="https://edu.google.com/coursebuilder/courses/pswg/1.2/assets/notes/Lesson3.5/Lesson3.5IntextandAdvancedSearch_Text_.html"&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DyaU4Ibw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seds.nl/assets/images/google-intext-query_censored.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DyaU4Ibw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://seds.nl/assets/images/google-intext-query_censored.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Holy sh1t. That’s ~89,900 results from Google. Can you imagine how much sensitive information there must be?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix this
&lt;/h2&gt;

&lt;p&gt;Well, first of all, find a better way to getting your source code to a remote server and simply pointing your web-server to that directory. If you don’t feel like finding a better way, or just want to keep things simple, here is what you need to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nginx
&lt;/h3&gt;

&lt;p&gt;Add the following telling Nginx to deny any request to a .git directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location ~ /.git/ {
    deny all;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Apache
&lt;/h3&gt;

&lt;p&gt;Add the following telling Apache to deny any request to a .git directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;DirectoryMatch "^/.*/\.git/"&amp;gt;
    Order deny,allow
    Deny from all
&amp;lt;/Directory&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The only question that remains is: Is there anyway you could extract a &lt;code&gt;.git&lt;/code&gt; from a web-server that has directory listing disabled? I haven’t looked much into it, but I wonder if there is anyway we could use &lt;code&gt;git&lt;/code&gt; against itself.&lt;/p&gt;

</description>
      <category>security</category>
      <category>git</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
