<?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: Noel Worden</title>
    <description>The latest articles on Forem by Noel Worden (@noelworden).</description>
    <link>https://forem.com/noelworden</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%2F297549%2F33484fc5-b395-46fe-b3ef-e518376db2aa.jpg</url>
      <title>Forem: Noel Worden</title>
      <link>https://forem.com/noelworden</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/noelworden"/>
    <language>en</language>
    <item>
      <title>Don't nuke your test ENVs</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 05 Nov 2025 02:50:19 +0000</pubDate>
      <link>https://forem.com/noelworden/dont-nuke-your-test-envs-4j6j</link>
      <guid>https://forem.com/noelworden/dont-nuke-your-test-envs-4j6j</guid>
      <description>&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: I know that modifying environment variables in tests is a controversial technique, but we do it on this project, so we have to do it &lt;em&gt;properly&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This week I learned that &lt;code&gt;Application.put_env/4&lt;/code&gt; can cause flaky tests, both when running sync and async.&lt;/p&gt;

&lt;p&gt;I was building out a test for a module that pulled data from &lt;code&gt;config.exs&lt;/code&gt;. It looked like this:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;and I set data as module attributes:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;When I started running the tests, I was getting intermittent failures. After some digging, I found that when the tests failed, the returned config list was not what I expected, it only contained a single key/value pair:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;I was using a new (to me) mocking library for my tests, so my first thought was that I was somehow overwriting the configs, or that the mocks were using a different set of test-specific configs. I tinkered with that, but it wasn't the case. Then, in the process of trying to narrow down the variables, I changed the test from &lt;code&gt;async: true&lt;/code&gt; to &lt;code&gt;async: false&lt;/code&gt;. I have had experiences in the past where async tests have data read/write conflicts, which I thought setting my test to &lt;code&gt;async: false&lt;/code&gt; would eliminate. But that didn't improve the flakiness, in fact, it made it worse. With no luck fixing the flake, I pinged my team, and got a great piece of advice: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"...any other test does an &lt;code&gt;Application.put_env&lt;/code&gt; and you're in for trouble"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lightbulb moment.&lt;/p&gt;

&lt;p&gt;I noticed a private function in another test that was modifying this same config. At first glance, it looked like it reset the config to its original state. The culprit:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;To me, what it looked like that private function was doing was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab that particular key/value pair&lt;/li&gt;
&lt;li&gt;Update the value&lt;/li&gt;
&lt;li&gt;Return that updated key/value&lt;/li&gt;
&lt;li&gt;After the test completes, reset the key/value to its original state and insert it back into the list of &lt;code&gt;MyApp.Example&lt;/code&gt; configs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But it's a bit deceiving, because the call:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;Does not merge into the existing config, it &lt;em&gt;overwrites&lt;/em&gt; the entire config with only the key/value passed. &lt;/p&gt;

&lt;p&gt;So, the &lt;code&gt;on_exit&lt;/code&gt; function reset the entire &lt;code&gt;MyApp.Example&lt;/code&gt; config to:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;Which meant that if my test ran after the test containing this private function, mine would fail because the necessary config key/values did not exist. And, my debugging attempt to change my test to &lt;code&gt;async: false&lt;/code&gt; didn't help, because our non-async tests generally run at the end of the test suite. The fix was to refactor that private function to restore the entirety of the original config in the &lt;code&gt;on_exit&lt;/code&gt; block, like this: &lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;p&gt;After I refactored that private function, I ran a script to execute the test suite 100x, and I saw no failures. Flake fixed! &lt;/p&gt;

&lt;p&gt;The lesson learned: If you must modify envs in tests, isolate them carefully or restore the full config explicitly to avoid cross-test pollution.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>thisweekilearned</category>
      <category>testing</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Import CSV &amp; Seed Data</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Tue, 01 Dec 2020 15:32:27 +0000</pubDate>
      <link>https://forem.com/noelworden/elixir-phoenix-importing-csv-data-seeding-data-2b7p</link>
      <guid>https://forem.com/noelworden/elixir-phoenix-importing-csv-data-seeding-data-2b7p</guid>
      <description>&lt;h4&gt;
  
  
  Goals
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Seed the &lt;code&gt;destinations&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I finished &lt;a href="https://dev.to/noelworden/elixir-phoenix-project-create-first-schema-run-tests-in-docker-5979"&gt;setting up the first schema&lt;/a&gt; with everything needed to CRUD (create / edit / update / delete) a record in the &lt;code&gt;destinations&lt;/code&gt; table. The views and forms are functional, but they definitely need some love, particularly the &lt;code&gt;index&lt;/code&gt; view. But before I dive into any styling, it would be beneficial to get some data into the &lt;code&gt;index&lt;/code&gt; table. I could have used the app's newly created html forms and generated the data one record at a time, but its far more efficient -and beneficial down the road- to utilize the &lt;code&gt;seeds.exs&lt;/code&gt; file. Using this method, the database can be populated quickly and consistently.&lt;/p&gt;

&lt;h4&gt;
  
  
  Seed the &lt;code&gt;destinations&lt;/code&gt; table
&lt;/h4&gt;

&lt;p&gt;Phoenix ships with a seed file, located at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;priv/repo/seeds.exs&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Functions in the seed file don't have to be complex, it's simply an automated way to insert data into the table. A lot of times the data being inserted is fake, and primarily used as a kind of placeholder. But in my case I already had a spreadsheet with all the data and figured that since I was going through this process to inject data, it might as well be real data. Taking the time to write functionality to ingest data from a spreadsheet would also allow me to batch upload data through the browser at some point, which could be handy. Lastly, this kind of spreadsheet ingestion was handled in my last work project, so I had some experience with it, as well as some existing functions to guide me through the process. &lt;/p&gt;

&lt;p&gt;Because of the potential dual use of the ingestion code I would be writing, I created a new &lt;code&gt;CSVUtil.ex&lt;/code&gt; file, and housed it under the &lt;code&gt;Mapping&lt;/code&gt; context. I did a bit of digging to see what libraries were available for processing a CSV (that's the format I exported the spreadsheet to for ingestion), and &lt;a href="https://hexdocs.pm/nimble_csv/NimbleCSV.html"&gt;NimbleCSV&lt;/a&gt; was the clear front runner. I wasn't surprised, as that's what we used on my work project. &lt;/p&gt;

&lt;p&gt;Knowing that I would use the same library as I already had experience with, I took an iterative approach to writing the functionality. Basically, what happened over the course of a day was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Starting with the work project functions as a rough scaffold, I implemented my own version of CSV ingestion.&lt;/li&gt;
&lt;li&gt;My initial version was a little verbose and clunky, but functional.&lt;/li&gt;
&lt;li&gt;I started refactoring my work and seeing how and where it was similar to the work project code.&lt;/li&gt;
&lt;li&gt;Ultimately I ended up with a good bit of similarity to the work project code, but with a much better understanding of what was happening from start to finish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I will be discussing the end result of that process shortly. But first things first, the &lt;code&gt;NimbleCSV&lt;/code&gt; library needed to be added to the dependencies in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then I fetched the new dependency with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mix deps.get&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once that finished, I rebuilt the docker image:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And, finally, spun it up again:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With the library added to the project, I added an alias of the implementation of &lt;code&gt;NimbleCSV&lt;/code&gt; I planned on using in &lt;code&gt;CSVUtil.ex&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This allows me to just call &lt;code&gt;CSV.&amp;lt;function&amp;gt;&lt;/code&gt; instead of &lt;code&gt;NimbleCSV.RFC4180.&amp;lt;function&amp;gt;&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;Pulling from my previous experience, I knew I needed to either hardcode the CSV headers or grab them from the file. Initially I hardcoded them, but for future versatility I went with this function that extracts the headers and maps them to an index:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The breakdown of that function:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This takes in the CSV file and streams it line by line, which is perfect creating a record from each row of the CSV. This function alone only returns a struct with data about the file, its best utilized when another function is piped into it.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This tells &lt;code&gt;File.stream!()&lt;/code&gt; to break that file down line by line, then parse it into a stream of rows. The default action of &lt;code&gt;parse_stream&lt;/code&gt; is to exclude the headers, so I need to explicitly state that I want to include the headers here. The rows aren't user-facing until they are looped over.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is returning only the first row of the stream, and dropping the rest. At this point the results start to take shape into something usable:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This takes that list of strings and creates a list of tuples, the string as the first element and its index as the other, like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And lastly:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This converts the list of tuples into a map, using the index value as the key and the string as the value:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The need for the indexing and conversion to key/value pairs will reveal itself in the next step.&lt;/p&gt;

&lt;p&gt;The next function, &lt;code&gt;csv_row_to_table_record/1&lt;/code&gt; calls the first, sets it as a variable, and then works through the rest of the CSV file, to insert it into the &lt;code&gt;destinations&lt;/code&gt; table:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I'll skip the first two pipes, since they were covered above, and start with:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That is taking each row, and adding an index to each field in that row. A small sample of the output looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then there is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Which is taking each of those rows, creating a new map from it, and using the indexing to match the header value from &lt;code&gt;column_names&lt;/code&gt; to the row value, the result of which is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And, finally, there is a custom function to use that map to insert the data into the table:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The goal with this function was to be able to update that CSV, execute the seeding file, and only have the new files be added to the database, so the standard create function:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Wouldn't work here, because it would add the entirety of the CSV to the table each time, instead of only the new records. This is what the custom function looks like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The argument &lt;code&gt;row&lt;/code&gt; is the map created in the pipe above the calling of this function. The &lt;code&gt;case&lt;/code&gt; is searching the &lt;code&gt;destination&lt;/code&gt; table for the lat/long coordinates created in the call above. If that search returns &lt;code&gt;nil&lt;/code&gt;, the map and &lt;code&gt;Mapping.create_destination&lt;/code&gt; are utilized to create and insert a new record. Because of the header/value pairing that happened in the creation of the map, I can reference the value of the fields with this syntax:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If those coordinates do exist, it will return a tuple instead of creating a new record.&lt;/p&gt;

&lt;p&gt;This logic might be easier to parse when seeing everything at one time, here is the file in its entirety:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The spreadsheet I've been using to hold my data up to this point is a Google Sheet. I exported it out as a CSV, and created a new folder at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;priv/repo/data&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To store this file an any potential future files of this nature.&lt;/p&gt;

&lt;p&gt;With all that in place, the code in &lt;code&gt;seeds.exs&lt;/code&gt; is actually only one line:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And, as the notes in the seed file mention, that can be executing by running:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Closing Thoughts
&lt;/h4&gt;

&lt;p&gt;This was definitely a more complex data seeding than is typically performed as the first seed of a new project. It would have taken a good amount of time to manually create dummy records, and if I ever needed to drop the database and rebuild it, I would have had to manually insert records again. Instead I took a bit more time and created reusable logic that can seed the database with actual records in quite literally the blink of an eye. I also now have the foundation to do more work with CSVs, which seems like a feasible option for mass uploading in the future.  &lt;/p&gt;

&lt;p&gt;As always, here is my &lt;a href="https://github.com/noelworden/atlas/tree/1e41d51f5e2b89e955343f20cbb544e78dba4e0f"&gt;repo&lt;/a&gt; at the end of this block of work. &lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixircasts.io/seeding-data-in-phoenix"&gt;https://elixircasts.io/seeding-data-in-phoenix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/nimble_csv/NimbleCSV.html"&gt;https://hexdocs.pm/nimble_csv/NimbleCSV.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/elixir/1.3.0/File.html#stream!/3"&gt;https://hexdocs.pm/elixir/1.3.0/File.html#stream!/3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://joyofelixir.com/11-files/"&gt;https://joyofelixir.com/11-files/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Create First Schema &amp; Run Tests in Docker</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Tue, 10 Nov 2020 15:50:58 +0000</pubDate>
      <link>https://forem.com/noelworden/elixir-phoenix-project-create-first-schema-run-tests-in-docker-5979</link>
      <guid>https://forem.com/noelworden/elixir-phoenix-project-create-first-schema-run-tests-in-docker-5979</guid>
      <description>&lt;h4&gt;
  
  
  Goal
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create Destinations schema under Mapping context&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Create Destinations schema under Mapping context
&lt;/h4&gt;

&lt;p&gt;The goal for this next step was to establish the first schema in the project, with the intention to then write the tests, and finally the views. In my previous projects I had always done this by hand, starting with the migration, then the schema, and then the context; and that was the plan for this work as well. But, plans changed, pretty dramatically. Having the time to explore and hopefully improve on my workflows and knowledge base, I spent some time researching before diving into the code. That research -unsurprisingly- led me to the the Phoenix Context &lt;a href="https://hexdocs.pm/phoenix/contexts.html"&gt;docs&lt;/a&gt;, which, led me to the &lt;a href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Html.html"&gt;&lt;code&gt;phx.gen.html&lt;/code&gt;&lt;/a&gt; generator. I've known about generators, but I had no idea that a generator existed that did so much. &lt;/p&gt;

&lt;p&gt;Initially I was on the fence about using the generator, on one hand it is incredibly convenient for the framework to generate &lt;em&gt;every&lt;/em&gt; file necessary to get a schema running, tested, and browser-ready. On the other hand, having all the work done automatically can lead to problems down the road, like debugging, because I'm not as intimately familiar with generated files as I would be with files I typed out by hand. Similar to the common idea that most people learn coding principles much better if they type it all out instead of copy/pasting it from the source. Ultimately I decided to use the generator. I have enough experience with the files being generated that I didn't feel the need to write them all out by hand. I also felt that it would be beneficial to know all the necessary bases were covered, and have that as a pull request to utilize as a reference for future work that I may write without a generator.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;phx.gen.html&lt;/code&gt; generator takes four arguments. The first is the context module name, then the schema module name, third is the schema module's plural name (to be used as the table name), and, optionally, the last is the list of fields and corresponding types. &lt;/p&gt;

&lt;p&gt;The schema I wanted to created had a good number of fields, my generation looked like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In that generation command, &lt;code&gt;Mapping&lt;/code&gt; is the context, &lt;code&gt;Destination&lt;/code&gt; is the schema module, &lt;code&gt;destinations&lt;/code&gt; the table name, and lastly the list of fields and their types. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;side note:&lt;/em&gt; That command could have been typed out as one long string, like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But by using the &lt;code&gt;\&lt;/code&gt; as an escape character, the command can be broken out over several lines to enhance readability.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one generation command created the context, schema, migration, all tests, and all views. The output showed all the files created and then instructions on two more steps needed to complete the process:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Executing the first step from the instructions created all the default the routes for this schema. For this case, the entirety of the default routes works because I intended on utilizing them all. I confirmed the routes generated as expected with this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose exec web mix phx.routes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Which returned:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The second step in the instructions was to execute the migration created in the generation, creating the &lt;code&gt;destinations&lt;/code&gt; table in the database. &lt;/p&gt;

&lt;p&gt;With the exception of including &lt;code&gt;null:false&lt;/code&gt; to a few the fields in the migration, all files created by the generator were good to go. I have some work to do to the generated html files, but that will be covered by a ticket down the road. After executing the migration command, I can navigate to &lt;code&gt;localhost:4000/destinations&lt;/code&gt; and I see the index page of that schema, with the ability to create a new record, as well as all the other record manipulating functionality I expect. It's actually pretty amazing how much was accomplished with that &lt;code&gt;phx.gen.html&lt;/code&gt; command. There are several &lt;code&gt;mix.phx&lt;/code&gt; commands, all of course do something different, and save a lot of typing. They can be found in the &lt;a href="https://hexdocs.pm/phoenix/mix_tasks.html#content"&gt;Mix Tasks&lt;/a&gt; section of the Phoenix &lt;a href="https://hexdocs.pm/phoenix/overview.html"&gt;documentation&lt;/a&gt;, or by typing &lt;code&gt;mix phx&lt;/code&gt; in the terminal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus - Running tests in the Docker container
&lt;/h4&gt;

&lt;p&gt;My initial plan was to separate out this work, but since the tests were included in the files produced by the generator I decided to tackle this and include it in the pull request. I hit some bumps in the road when changing the database configurations in &lt;code&gt;test.exs&lt;/code&gt;, to get the tests to run within the container. The process was involved enough that it warranted its own &lt;a href="https://dev.to/noelworden/a-few-caveats-to-running-elixir-tests-in-containers-and-ci-21ef"&gt;post&lt;/a&gt;. The high-level overview is that the &lt;code&gt;hostname&lt;/code&gt; of the testing database needs to be &lt;code&gt;"db"&lt;/code&gt; to run the tests in a container, but &lt;code&gt;"localhost"&lt;/code&gt; for the tests to run in CI. The solution was to use &lt;a href="https://hexdocs.pm/elixir/System.html#get_env/2"&gt;&lt;code&gt;System.get_env/2&lt;/code&gt;&lt;/a&gt; in the database configuration logic, and add an &lt;code&gt;env&lt;/code&gt; field in the CI testing configuration.&lt;/p&gt;

&lt;p&gt;The update to the &lt;code&gt;elixir.yml&lt;/code&gt; file took this step:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And added an environmental variable of &lt;code&gt;DB_HOSTNAME&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Then the &lt;code&gt;hostname&lt;/code&gt; field of the testing database configuration found at &lt;code&gt;test.exs&lt;/code&gt; went from this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Where &lt;code&gt;System.get_env/2&lt;/code&gt; is looking for the environmental variable set in the &lt;code&gt;elixir.yml&lt;/code&gt; CI file. When that environmental variable is present (when tests are being run in the CI) it sets &lt;code&gt;hostname&lt;/code&gt; to the variable's value, &lt;code&gt;"localhost"&lt;/code&gt;, allowing the tests to run in the CI build. And if the environmental variable is not found, the &lt;code&gt;hostname&lt;/code&gt; defaults to &lt;code&gt;"db"&lt;/code&gt;, allowing for the test to properly run in a container. &lt;/p&gt;

&lt;h4&gt;
  
  
  Closing Thoughts
&lt;/h4&gt;

&lt;p&gt;With the completion of this work, I can now Create, Read, Update, and Delete (CRUD) records in the &lt;code&gt;destination&lt;/code&gt; table. The index view is currently a little rough, because of the size of the table that is being displayed, but that task is for another time. I can now also execute tests in the Docker container with this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose exec web mix test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the tests also run as part of the CI check.&lt;/p&gt;

&lt;p&gt;Having a working schema sets me up well for my next task, which is to utilize the &lt;code&gt;seeds.exs&lt;/code&gt; file to populate the new table with sample data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/noelworden/atlas/tree/e33a6f3e2b9f9eda2b2cc6f91a16e55a0367d593"&gt;This&lt;/a&gt; is what my repo looks like at the end of this block of work. &lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elixircasts.io/phoenix-contexts"&gt;https://elixircasts.io/phoenix-contexts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/contexts.html"&gt;https://hexdocs.pm/phoenix/contexts.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/mix_tasks.html#content"&gt;https://hexdocs.pm/phoenix/mix_tasks.html#content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Html.html"&gt;https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Html.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.community/t/workflow-fails-when-running-steps-in-a-container/16123/2"&gt;https://github.community/t/workflow-fails-when-running-steps-in-a-container/16123/2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Dockerizing</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 14 Oct 2020 15:23:09 +0000</pubDate>
      <link>https://forem.com/noelworden/elixir-phoenix-project-dockerizing-10p7</link>
      <guid>https://forem.com/noelworden/elixir-phoenix-project-dockerizing-10p7</guid>
      <description>&lt;h4&gt;
  
  
  Goals:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Dockerize project&lt;/li&gt;
&lt;li&gt;Update README with new instructions on launching app with Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Dockerize project
&lt;/h4&gt;

&lt;p&gt;Although this is implied with all of my writing, it's especially true with Docker, so it bears to be said explicitly: I am by no means a Docker expert. What I will be talking about in this post are the steps I took to get my project running in Docker from online resources and my past experience. If there is any aspect of what I'm about to talk about that could be improved, I would greatly appreciate any feedback. With that caveat out of the way, here is what I did to build my app in Docker images. &lt;/p&gt;

&lt;p&gt;Actually, before I dive into the files, here's a quick refresher on whats what in the world of Docker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;Dockerfile&lt;/code&gt; builds an &lt;em&gt;image&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;container&lt;/em&gt; is started from that image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker-compose.yml&lt;/code&gt; defines which containers (aka services) make up a complete app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step was to create a &lt;code&gt;Dockerfile&lt;/code&gt;, which is a file of specifications that Docker uses to build an image. For my &lt;code&gt;Dockerfile&lt;/code&gt; I used an image from &lt;a href="https://hub.docker.com/"&gt;Docker Hub&lt;/a&gt; that I have used in the past, &lt;a href="https://hub.docker.com/r/bitwalker/alpine-elixir-phoenix/"&gt;alpine-elixir-phoenix&lt;/a&gt;. I have been happy with it, and I'm also familiar with how to setup a &lt;code&gt;Dockerfile&lt;/code&gt; with it. I used the image &lt;a href="https://hub.docker.com/r/bitwalker/alpine-elixir-phoenix/"&gt;docs&lt;/a&gt; as a starting point for my &lt;code&gt;Dockerfile&lt;/code&gt; but ended up simplifying it a bit for my needs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Heres the breakdown of the file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is declaring which version of elixir will be used.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is executing the &lt;code&gt;RUN&lt;/code&gt; command to create a new directory ,&lt;code&gt;/app&lt;/code&gt;. Then &lt;code&gt;WORKDIR&lt;/code&gt; is setting that newly created folder as the working directory.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This is executing the &lt;code&gt;COPY&lt;/code&gt; command to move the &lt;code&gt;mix.exs&lt;/code&gt; and &lt;code&gt;mix.lock&lt;/code&gt; files from the local directory into the image directory, then using &lt;code&gt;RUN&lt;/code&gt; to execute a &lt;code&gt;mix&lt;/code&gt; command in the image directory.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Similar to the previous command, this is executing &lt;code&gt;COPY&lt;/code&gt; to move the necessary &lt;code&gt;assets&lt;/code&gt; from the local directory to the image, then &lt;code&gt;RUN&lt;/code&gt; to execute an &lt;code&gt;npm install --prefix&lt;/code&gt; into the folder on the image.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This copies the rest of the files and folders from the root of the local directory to the root of the image.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Lastly, an execution of &lt;code&gt;CMD&lt;/code&gt; to start the server&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;Dockerfile&lt;/code&gt; complete, the next step was to create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. Like I said earlier, this file defines the containers that will make up the complete app. There's a good amount of content, so I'll utilize comments in the example code to explain what is what, instead of listing everything out individually:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;One last thing that I needed to do before taking this for a test run was to change to the &lt;code&gt;dev.exs&lt;/code&gt; file. This change was not on &lt;em&gt;any&lt;/em&gt; of the tutorials I used, and it caused me enough trouble that when I found the solution I actually wrote up a standalone &lt;a href="https://dev.to/noelworden/docker-connecting-an-elixir-phoenix-app-container-and-database-container-2n0a"&gt;post&lt;/a&gt; about it. The change is pretty painless, the &lt;code&gt;hostname&lt;/code&gt; field of the &lt;code&gt;Repo&lt;/code&gt; config needs to be updated from &lt;code&gt;localhost&lt;/code&gt; to &lt;code&gt;db&lt;/code&gt; to match the name of the container running the database:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With the two docker files created, the update to &lt;code&gt;dev.exs&lt;/code&gt;, and &lt;a href="https://docs.docker.com/docker-for-mac/install/"&gt;Docker for Mac&lt;/a&gt; installed an running on my machine, the app is up and running with three commands (I recommend executing in two tabs of the terminal):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminal Tab 1

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once its spun up, the &lt;code&gt;db&lt;/code&gt; container shows the following error:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Although the &lt;code&gt;db&lt;/code&gt; container is up and running, the app is looking for the database that is declared in &lt;code&gt;dev.exs&lt;/code&gt;, in this case &lt;code&gt;atlas_dev&lt;/code&gt;. The third command will take care of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminal Tab 2

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose exec web mix ecto.setup&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That command uses &lt;code&gt;exec web&lt;/code&gt; to execute the &lt;code&gt;mix&lt;/code&gt; command in the currently running &lt;code&gt;web&lt;/code&gt; container. The &lt;code&gt;ecto.setup&lt;/code&gt; command is from the &lt;code&gt;mix.exs&lt;/code&gt; file, and runs a list of commands:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Although I don't have any migrations or seeds at the moment, I still use that command, it's mostly a muscle memory thing at this point.&lt;/p&gt;

&lt;p&gt;With that command executed in a second tab, the logs in the first tab no longer display an error, and everything is ready to go. The app can now be viewed at &lt;a href="https://dev.tohttp:localhost:4000"&gt;localhost:4000&lt;/a&gt;. Of course, since I have yet to actually code anything in this new app, it's still the generic Phoenix startup page, but that will change soon.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update README with new instructions on launching app with Docker
&lt;/h4&gt;

&lt;p&gt;With the project Dockerized, I also updated the README with new instructions on how to spin up the app:&lt;/p&gt;




&lt;h2&gt;
  
  
  Spinning up project with Docker
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://docs.docker.com/docker-for-mac/install/"&gt;Docker for Mac&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;In one terminal tab:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;In a second tab, once the two commands in the first tab are completed:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose exec web mix ecto.setup&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If everything spins up with no errors, site will be live at &lt;a href="http://localhost:4000"&gt;localhost:4000&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;It's essentially the steps from above, but I believe that keeping docs updated is important, so it's worth noting as part of my process&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus - Ignoring files for a faster Docker build
&lt;/h4&gt;

&lt;p&gt;A file can be created that is similar to what &lt;code&gt;.gitignore&lt;/code&gt; does for git, but for Docker. This file is &lt;code&gt;.dockerignore&lt;/code&gt; and Docker looks for this file before each build to see if there are files that can be skipped in the execution of the build. Skipping files creates a smaller image and therefore a faster build. I pulled the contents of my &lt;code&gt;.dockerignore&lt;/code&gt; from the Distillery &lt;a href="https://hexdocs.pm/distillery/guides/working_with_docker.html"&gt;hexdocs&lt;/a&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Adding this file was one of my last steps in the process, and I kind of regret that, as the build is &lt;em&gt;noticeably&lt;/em&gt; faster with Docker ignoring these files. Adding this earlier in the process would have saved me a lot of time while experimenting with the proper &lt;code&gt;Dockerfile&lt;/code&gt; and &lt;code&gt;docker-compose.yml&lt;/code&gt; configurations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Closing thoughts
&lt;/h4&gt;

&lt;p&gt;Docker will be the last devops aspect I am going to setup. I am ready to do some feature coding and get that default Phoenix splash page out of there. But, I am very happy that I have taken the time to set my project up with these tools and make the process as streamlined as possible right out of the gate. From here on out I can basically just concern myself with features and whatever random thing I want to try, and all the checks I have in place will keep my code tidy and easy to deploy. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/noelworden/atlas/tree/782b262ceef922082c0b66fb324262fecf41b7e3"&gt;This&lt;/a&gt; is my repo at the end of this block of work.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;https://docs.docker.com/engine/reference/builder/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/r/bitwalker/alpine-elixir-phoenix/"&gt;https://hub.docker.com/r/bitwalker/alpine-elixir-phoenix/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/swlh/use-docker-to-create-an-elixir-phoenix-development-environment-e1a81def1d2e"&gt;https://medium.com/swlh/use-docker-to-create-an-elixir-phoenix-development-environment-e1a81def1d2e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codereviewvideos.com/course/elixir-phoenix-and-docker-tutorial/video/docker-compose-tutorial-for-elixir-and-phoenix-framework"&gt;https://codereviewvideos.com/course/elixir-phoenix-and-docker-tutorial/video/docker-compose-tutorial-for-elixir-and-phoenix-framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codefresh.io/docker-tutorial/not-ignore-dockerignore-2/"&gt;https://codefresh.io/docker-tutorial/not-ignore-dockerignore-2/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Establish Hosting Service</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 07 Oct 2020 14:24:44 +0000</pubDate>
      <link>https://forem.com/noelworden/elixir-phoenix-project-establish-hosting-service-4km0</link>
      <guid>https://forem.com/noelworden/elixir-phoenix-project-establish-hosting-service-4km0</guid>
      <description>&lt;h4&gt;
  
  
  Goals:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Establish a hosting service&lt;/li&gt;
&lt;li&gt;Update README with deploy steps&lt;/li&gt;
&lt;li&gt;Setup custom domain to point to new environment&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Establish a hosting service
&lt;/h4&gt;

&lt;p&gt;A project running locally on my machine is great, but it doesn't mean much if that's the only place it exists. It might seem a bit premature, considering that at this point my entire project is still the default Phoenix splash page. But getting a hosting environment setup early means that new features will be able to go live as soon as they are merged. I started the process by digging around the web to see what others had done (noticing a pattern yet?). And I was a bit surprised that there is a whole service targeted specifically to hosing Elixir/Phoenix projects that I had not heard of: &lt;a href="https://www.gigalixir.com/"&gt;Gigalixir&lt;/a&gt;. What I was &lt;em&gt;not&lt;/em&gt; surprised by was that there is an entire &lt;a href="https://hexdocs.pm/phoenix/deployment.html#content"&gt;Deployment&lt;/a&gt; section of the Phoenix hexdocs, and in that section there is a whole subsection of how to &lt;a href="https://hexdocs.pm/phoenix/gigalixir.html#content"&gt;deploy to Gigalixir&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But, before I go any further, I'm sure someone out there is thinking "why not Heroku?". In a nutshell, Heroku is not setup to give access to all of the features of an Elixir/Phoenix app, like node clustering. Not being partial to any particular hosting service, I figured why not setup my hosting with a service that is made for Elixir/Phoenix?&lt;/p&gt;

&lt;p&gt;I ended up walking through the Gigalixir &lt;a href="https://gigalixir.readthedocs.io/en/latest/getting-started-guide.html"&gt;Getting Started Guide&lt;/a&gt;, and I have to say, the process was pretty painless. The Gigalixir docs are very detailed, and searchable. Because of the level of detail in their docs, I'm not going to write out my entire process, because I literally just followed the docs through step by step. I will note that I got a bit hung up in the &lt;a href="https://gigalixir.readthedocs.io/en/latest/getting-started-guide.html#specify-versions"&gt;Specify Versions&lt;/a&gt; section, because my local versions of &lt;code&gt;elixir&lt;/code&gt; and &lt;code&gt;erlang&lt;/code&gt; were newer than what were specified in the docs.&lt;/p&gt;

&lt;p&gt;My local: &lt;br&gt;
&lt;code&gt;elixir&lt;/code&gt; -&amp;gt; &lt;code&gt;1.10.4&lt;/code&gt;&lt;br&gt;
&lt;code&gt;erlang&lt;/code&gt; -&amp;gt; &lt;code&gt;23&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Docs specs:&lt;br&gt;
&lt;code&gt;elixir&lt;/code&gt; -&amp;gt; &lt;code&gt;1.10.3&lt;/code&gt;&lt;br&gt;
&lt;code&gt;erlang&lt;/code&gt; -&amp;gt; &lt;code&gt;22.3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I attempted to declare these new versions in the &lt;code&gt;elixir_buildpack.config&lt;/code&gt; file that Gigalixir uses to set environment versioning, but when I tried to push up to the service was giving an error stating that those versions couldn't be found. I tinkered with things for a bit, but the only way I could get a push to this new staging environment to be successful was to use the environment specs given in the docs. It's definitely less than desirable to have a local version be different than in a staging environment, but it's a minor version difference, and I know that my next step in this app is to dockerize everything, and there I will take the steps to ensure the versions match.&lt;/p&gt;

&lt;p&gt;Another thing to note is that while setting up my Github repository I switched my primary branch name from &lt;code&gt;master&lt;/code&gt; to &lt;code&gt;main&lt;/code&gt;. It seems that Gigalixir has not quite caught up with this optional change, and in the &lt;a href="https://gigalixir.readthedocs.io/en/latest/getting-started-guide.html#deploy"&gt;Deploy&lt;/a&gt; step it has this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push gigalixir master&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But, thats basically shorthand, stating that &lt;code&gt;master&lt;/code&gt; from Github should be pushed to &lt;code&gt;master&lt;/code&gt; in the staging environment. Since I don't have a &lt;code&gt;master&lt;/code&gt; branch, I get the following error:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The fix is pretty simple, it just requires a more verbose command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git push gigalixir main:master&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That command is stating that the &lt;code&gt;main&lt;/code&gt; branch of Github should be pushed to the &lt;code&gt;master&lt;/code&gt; branch of staging&lt;/p&gt;

&lt;p&gt;One last note that was not noted in the Getting Started Guide is that the remote can be renamed. By default Gigalixir named the remote &lt;code&gt;gigalixir&lt;/code&gt; but I am more used to referencing remotes by their purpose, like &lt;code&gt;staging&lt;/code&gt; or &lt;code&gt;production&lt;/code&gt;. So I ran this command to update the name of my remote:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git remote rename gigalixir staging&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Although there were a few small hiccups, all in all the process to setup a staging environment for the project was relatively painless. I have setup a few Heroku environments back in the day, and this process seems remarkably similar. I would strongly recommend at least skimming through the entirety of the Gigalixir &lt;a href="https://gigalixir.readthedocs.io/en/latest/"&gt;docs&lt;/a&gt; as they are chock full of useful information.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update README with deploy steps
&lt;/h4&gt;

&lt;p&gt;In the vein of trying to keep within the ream of best practices I felt like it would be beneficial to document the deploy steps in the README. I've been on more than a few projects where I was the second or third engineer onboarded and there was no documentation on how to perform relatively essential tasks. This is what I included in the project's README:&lt;/p&gt;




&lt;h2&gt;
  
  
  Deploying to staging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Hosted by Gigalixir, docs can be found &lt;a href="https://gigalixir.readthedocs.io/en/latest/"&gt;here&lt;/a&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It should be noted that the docs are &lt;em&gt;very&lt;/em&gt; good, and searchable&lt;/li&gt;
&lt;li&gt;Once the CLI is installed, &lt;code&gt;gigalixir help&lt;/code&gt; is also very detailed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Project URLs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://atlas-staging.gigalixirapp.com/"&gt;https://atlas-staging.gigalixirapp.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://atlas-production.gigalixirapp.com/"&gt;https://atlas-production.gigalixirapp.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install Gigalixir CLI (with homebrew)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;brew tap gigalixir/brew &amp;amp;&amp;amp; brew install gigalixir&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Log into Gigalixir
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gigalixir login&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Verify login was successful
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gigalixir account&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup git remote
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to project folder&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gigalixir git:remote atlas-staging&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Confirm remote
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git remote -v&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  If desired, rename remote (which defaulted to &lt;code&gt;gigalixir&lt;/code&gt;) to &lt;code&gt;staging&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git remote rename gigalixir staging&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Push to staging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Any branch can be pushed to the staging site&lt;/li&gt;
&lt;li&gt;Branches need to be pushed to Github before being pushed to staging

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git push staging &amp;lt;branch name&amp;gt;:master&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Main vs Master
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This project's main branch is named &lt;code&gt;main&lt;/code&gt;, but Gigalixir is expecting it to be named &lt;code&gt;master&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Because of this, when pushing &lt;code&gt;main&lt;/code&gt; to staging, it &lt;em&gt;cannot&lt;/em&gt; be done with the shorthand:
&lt;code&gt;git push staging master&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Until a fix is made by Gigalixir, the following syntax must be used to push:
&lt;code&gt;git push staging main:master&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Executing &lt;code&gt;mix&lt;/code&gt; Commands in Staging
&lt;/h2&gt;

&lt;p&gt;The app is currently setup to be able to run mix commands on the staging environment&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;run&lt;/code&gt; command
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This can be used to run a shell command as a job in a separate container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gigalixir run ...&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;mix&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Any &lt;code&gt;mix&lt;/code&gt; command available locally can be executing on staging utilizing &lt;code&gt;run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gigalixir run mix &amp;lt;command here&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Executing a migration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gigalixir run mix ecto.migrate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The logs do not automatically show, to view the logs

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gigalixir logs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Viewing the app
&lt;/h2&gt;

&lt;h3&gt;
  
  
  To open the app in a browser
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gigalixir open&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;With this information, along with the slightly tweaked default &lt;code&gt;Spin up the Project&lt;/code&gt; steps, a new developer &lt;em&gt;should&lt;/em&gt; be able to pull down the project, get it spun up, and push work to staging all from the docs. I don't really plan on anyone besides me working on this in the foreseeable future, but solid documentation should be the goal of all projects, right?&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup custom domain
&lt;/h4&gt;

&lt;p&gt;Before I even started this project I dug around for a domain that I felt would be appropriate. It would be a bummer if I got 3 months into this project and I couldn't acquire a domain that had a name is a similar vein. I was able to purchase &lt;code&gt;anglingatlas.com&lt;/code&gt;, so I named the project and repo &lt;code&gt;atlas&lt;/code&gt; (I didn't want to type out &lt;code&gt;AnglingAtlas&lt;/code&gt; every time I had to reference something in the project). &lt;/p&gt;

&lt;p&gt;Gigalixir makes it pretty easy to assign a custom domain to the staging (or any other) environment. The one-liner can be found &lt;a href="https://gigalixir.readthedocs.io/en/latest/domain.html?highlight=domain#how-to-set-up-a-custom-domain"&gt;here&lt;/a&gt;. I should also point out that the Gigalixir web interface is pretty user-friendly as well. Now my staging environment can be found at &lt;a href="https://staging.theanglingatlas.com/"&gt;https://staging.theanglingatlas.com/&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Closing thoughts
&lt;/h4&gt;

&lt;p&gt;I kind of gravitated to all of these devops tasks because it's an aspect of projects that I haven't dealt with directly in quite some time. I was curious what it actually took to get all of this stuff in place. And since I was so far down this road I figured I might as well get it all taken care of. Once this is all squared away, I'll be able to just worry about the features. The last piece of this (I think) is going to be dockerizing the project.&lt;/p&gt;

&lt;p&gt;There aren't a ton of changes in the repo since a lot of this section was configuring Gigalixir, but &lt;a href="https://github.com/noelworden/atlas/tree/7298c0159e29548ed028614e0b544c0e88c88439"&gt;here&lt;/a&gt; is what it looks like after all of this configuration.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/deployment.html#content"&gt;https://hexdocs.pm/phoenix/deployment.html#content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gigalixir.com/"&gt;https://www.gigalixir.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gigalixir.readthedocs.io/en/latest/faq.html"&gt;https://gigalixir.readthedocs.io/en/latest/faq.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/git-guides/git-remote"&gt;https://github.com/git-guides/git-remote&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Ticket Workflow &amp; CI Integration</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Tue, 29 Sep 2020 14:11:17 +0000</pubDate>
      <link>https://forem.com/noelworden/part-2-ticket-workflow-ci-integration-kgo</link>
      <guid>https://forem.com/noelworden/part-2-ticket-workflow-ci-integration-kgo</guid>
      <description>&lt;h4&gt;
  
  
  Goals:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create ticket workflow, convert notes to tickets&lt;/li&gt;
&lt;li&gt;Integrate CI into the project&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Create ticket workflow, convert notes to tickets
&lt;/h4&gt;

&lt;p&gt;Although I am working on this new project solo and for the foreseeable future, I still wanted to have a way to create and track tasks. Back in the day, I used waffle.io but that project appears to have been axed. I liked waffle.io because of its Github integration and because it was relatively lightweight. I've used Jira and Atlassian, but those project managers seemed a bit heavy-handed for what I needed. After digging around a bit and asking some colleagues I settled on Github's own Issues and Projects. &lt;/p&gt;

&lt;p&gt;It seemed like a logical choice, the biggest win is that they are already a part of the repo, so its one less service I need to keep track of. It's also not any more complex than I need it to be, I can keep it lightweight and nimble. My current workflow is to first create an Issue ticket, mostly just a title, to get my thoughts documented. If I have notes at the time of creation I add them, if not I leave it blank. The order of the issue tickets is trivial, that's where Projects come in. Projects is basically a kanban board, like Trello, Jira, etc. My flow with the Project board is that I pull in 4-8 issue tickets at a time, so I can see a short runway, then move the ticket across the board as the task progresses. &lt;/p&gt;

&lt;p&gt;I recognize that I'm using both Issues and Projects at their minimum capacity, but at the moment that serves my needs. After all, I can always expand and modify my workflow, but this is a good starting point. The list of Issues for my project can be found &lt;a href="https://github.com/noelworden/atlas/issues"&gt;here&lt;/a&gt;, and the Project board &lt;a href="https://github.com/noelworden/atlas/projects/1"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Integrate CI into the project
&lt;/h4&gt;

&lt;p&gt;This was a big one for me. A lot of the tutorials and walk-throughs I came across in &lt;a href="https://dev.to/noelworden/part-1-setup-elixir-phoenix-project-5fpj"&gt;Part 1&lt;/a&gt; jumped from the creation of the project right into something like tweaking the CSS setup or generating the first migration. The longer a project goes on without incorporating some kind of CI (continuous integration), the bigger headache it is going to be to get the tests to pass. I feel like it's much better to get integration dealt with right out of the gate and &lt;em&gt;hopefully&lt;/em&gt; never have to think about it again.&lt;/p&gt;

&lt;p&gt;Github has made it a lot easier than I had remembered to setup CI. The entire process can be done in the through Github web interface by clicking  &lt;code&gt;Actions &amp;gt; New workflow&lt;/code&gt;. Github suggests an Elixir-based workflow, clicking &lt;code&gt;Set up this workflow&lt;/code&gt; brought me to the Github editor, where it has a file named &lt;code&gt;elixir.yml&lt;/code&gt; setup to be added to a new folder structure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;./.gihhub/workflows/elixir.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is what the default file looks like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Referencing a &lt;a href="https://hashrocket.com/blog/posts/build-the-ultimate-elixir-ci-with-github-actions#setting-up-mix-dependency-cache"&gt;tutorial&lt;/a&gt;, I went ahead and added a formatting check to the end of the file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And committed the file via the Github web interface. At that point this was the entire &lt;code&gt;elixir.yml&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;On the first run of that CI configuration I got an error that my tests weren't passing. I did some research and found that I needed to add some code to include a database for the tests to run on:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So, now the updated &lt;code&gt;elixir.yml&lt;/code&gt; looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With that database setup, the tests passed, and I had that very satisfying green dot next to the pull request. Currently the CI was confirming that my tests pass and that the code was formatted properly. I was also interested in a service to analyze the code for consistency. I accomplished this by adding &lt;a href="https://github.com/rrrene/credo"&gt;Credo&lt;/a&gt; to the project. Once included in the &lt;code&gt;mix.exs&lt;/code&gt; file, Credo can be run locally with &lt;code&gt;mix credo&lt;/code&gt; and it can be incorporated into the CI by adding the following line to &lt;code&gt;elixir.yml&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I added the &lt;code&gt;--strict&lt;/code&gt; flag because I figure if I'm going to use a tool like this, I might as well use it to the fullest extent. With that addition, this is my final &lt;code&gt;elixir.yml&lt;/code&gt; file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To my surprise, Credo actually found a few syntax errors in the Phoenix-generated code, so I ended fixing those and pushing up a small refactor commit to get the CI green again. It's worth noting that the compile time of Credo has slowed significantly with modern versions of Elixir, as noted in this &lt;a href="https://github.com/rrrene/credo/issues/788"&gt;issue&lt;/a&gt;. I'm not downgrading my Elixir version or doing anything to handle this, as it still meets my needs, and I have the time to wait for the checks to complete. &lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus - Include CI Status Badge in README
&lt;/h4&gt;

&lt;p&gt;One of the articles I was referencing through this CI work also included an example of how to include the CI badge in the repo's README. I mean, why not? It will be pretty gratifying to see that green CI tag every time I'm in my repo. As far as the markdown goes, it's basically an image tag, being linked to a Github-generated &lt;code&gt;svg&lt;/code&gt;. This is what my my image tag looks like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I'll break it down, since it took me two commits to get it right:&lt;/p&gt;

&lt;p&gt;A basic image tag in markdown is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So, in the case of CI badge, the first chunk:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Is declaring that its an image, and the alt text is &lt;code&gt;Elixir CI&lt;/code&gt;. For what its worth, it would also work if the alt text were blank:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And the second chunk:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Is the source of the image file. The URL breaks down as such:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;https://github.com/noelworden&lt;/code&gt; -&amp;gt; my Github account&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/atlas&lt;/code&gt; -&amp;gt; the project repo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/workflows&lt;/code&gt; -&amp;gt; the folder where the CI file is contained&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/Elixir%20CI&lt;/code&gt; -&amp;gt; the CI file I'd like to see the status of

&lt;ul&gt;
&lt;li&gt;It should be noted that its necessary to use URI-encoding to include the space in the &lt;code&gt;name&lt;/code&gt; field of the file &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn't realize this until I had already coded it wrong once and merged it (🤦‍♂️), but that image link can be tested and confirmed in any markdown previewer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bonus - Create Pull Request Description Template
&lt;/h4&gt;

&lt;p&gt;A pull request template wasn't any part of my original plan for this block of work, but I'm still figuring out my commit and pull request workflow. I had merged a handful of pull requests to get all of this CI work up and running correctly and realized that I should have been including the Issue number in the pull request descriptions. Knowing that I would forget to include that detail in future pull requests I figured it would be worth my time to incorporate a pull request template.&lt;/p&gt;

&lt;p&gt;The file is a markdown file, that Github will look for when generating a new pull request. For Github to recognize it, the new file needed to be created and named: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;PULL_REQUEST_TEMPLATE.md&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This file can be stored in any of the following places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the project root -&amp;gt; &lt;code&gt;atlas &amp;gt; PULL_REQUEST_TEMPLATE.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;in a &lt;code&gt;docs&lt;/code&gt; folder -&amp;gt; &lt;code&gt;atlas &amp;gt; docs &amp;gt; PULL_REQUEST_TEMPLATE.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;in a hidden &lt;code&gt;.github&lt;/code&gt; folder -&amp;gt; &lt;code&gt;atlas &amp;gt; .github &amp;gt; PULL_REQUEST_TEMPLATE.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my original implementation of this template file I put it in the &lt;code&gt;docs&lt;/code&gt; folder. But, as I write this and am thinking about it more, Im going to move it to the &lt;code&gt;.github&lt;/code&gt; folder. The &lt;code&gt;.github&lt;/code&gt; folder already exists because of the implementation of the CI workflow, and it feels more appropriate to have this Github-specific file there than in a &lt;code&gt;docs&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;In my case, I just wanted to ensure I always included the Issue number, so my template for the moment is simply one line:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But, of course, a template can as detailed as necessary for the given project. &lt;/p&gt;

&lt;h4&gt;
  
  
  Closing thoughts
&lt;/h4&gt;

&lt;p&gt;With these four items complete, I feel like my project is in the realm of &lt;em&gt;best practices&lt;/em&gt;. I can create and track tasks, have continuous integration setup, and have the ability to run a linter locally. I can also see the status of the project's continuous integration at a glance, and have a simple pull request template setup. Since I'm in the mode of laying the groundwork for the project, the next step will be setting up a hosting environment. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/noelworden/atlas/tree/6e1c8ab240fb65a0463bc938fa17ce57a8893c14"&gt;This&lt;/a&gt; is what my repo looks like at the end of this block of work.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#adding-a-workflow-status-badge-to-your-repository"&gt;https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#adding-a-workflow-status-badge-to-your-repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hashrocket.com/blog/posts/build-the-ultimate-elixir-ci-with-github-actions#setting-up-mix-dependency-cache"&gt;https://hashrocket.com/blog/posts/build-the-ultimate-elixir-ci-with-github-actions#setting-up-mix-dependency-cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lobotuerto.com/blog/elixir-continuous-integration-with-github-actions/"&gt;https://lobotuerto.com/blog/elixir-continuous-integration-with-github-actions/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/enterprise/2.15/user/articles/creating-a-pull-request-template-for-your-repository"&gt;https://docs.github.com/en/enterprise/2.15/user/articles/creating-a-pull-request-template-for-your-repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Elixir/Phoenix Project: Project Setup</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 23 Sep 2020 15:04:45 +0000</pubDate>
      <link>https://forem.com/noelworden/part-1-setup-elixir-phoenix-project-5fpj</link>
      <guid>https://forem.com/noelworden/part-1-setup-elixir-phoenix-project-5fpj</guid>
      <description>&lt;h4&gt;
  
  
  Goals:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create new Elixir/Phoenix project and get it running on my local machine&lt;/li&gt;
&lt;li&gt;Initialize git and push to Github&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Before I took the dive in creating my new Elixir/Phoenix project I did what I bet most people would do, and typed something like &lt;em&gt;Creating Elixir Phoenix Project&lt;/em&gt; into my favorite search engine. That produced plenty of hits, and I looked at the first steps of a handful of them. Then I took a look at &lt;a href="https://hexdocs.pm/"&gt;hexdocs&lt;/a&gt;. What is hexdocs? Hexdocs is the source of documentation for all the hex packages for Erlang (which is the base language for Elixir). &lt;em&gt;Pheonix&lt;/em&gt; is a package for Elixir, and is managed by hex, and as a result has amazing &lt;a href="https://hexdocs.pm/phoenix/overview.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create new project and get it running on my local machine
&lt;/h4&gt;

&lt;p&gt;I took a look at the other blog posts and tutorials to just double check there wasn't something new or improved from the official docs that I should incorporate into my new project. It appears that everyone is going through the same steps as is recommended in the documentation, so thats what I did. If you are new to Elixir/Phoenix you might be surprised by just how good the hexocs are. In fact, they are so good that I'm not going to rewrite the step-by-step instructions, but instead simply include the links for &lt;a href="https://hexdocs.pm/phoenix/installation.html"&gt;installation&lt;/a&gt; and how to get a project &lt;a href="https://hexdocs.pm/phoenix/up_and_running.html#content"&gt;up an running&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Initialize git and push to Github
&lt;/h4&gt;

&lt;p&gt;With the new project working locally, I wanted to get it pushed up to Github. Again, great documentation for this whole process. First, I needed to initialize &lt;code&gt;git&lt;/code&gt; in my newly created project folder. The documentation for that can be found &lt;a href="https://github.com/git-guides/git-init"&gt;here&lt;/a&gt;. Once that was setup, I needed to create a new Github repo to push this project to. Being that I was already signed into Github, I navigated to &lt;a href="https://github.com/new"&gt;https://github.com/new&lt;/a&gt;. There are a few options when setting up a new repo, but I was fine just entering the new repo name and keeping it public. The Phoenix generator already created a &lt;code&gt;README&lt;/code&gt; and &lt;code&gt;.gitignore&lt;/code&gt; file, and if I decide I want a license I can add it later. Once the repo was created, Github provided instructions on how to link this new repo with the newly created project, I think this &lt;a href="https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line"&gt;documentation&lt;/a&gt; is a bit more verbose in what needs to be done and why. Following those instructions, all of my Phoenix-generated files are in my newly created repo.&lt;/p&gt;

&lt;p&gt;There isn't a ton to see, but &lt;a href="https://github.com/noelworden/atlas/tree/d0f6f02eb32093e2311eb3f6b5785dc7f343b761"&gt;this&lt;/a&gt; is what my repo looks after completing the goals of this post.&lt;/p&gt;

&lt;h4&gt;
  
  
  Closing thoughts
&lt;/h4&gt;

&lt;p&gt;Now, I know it might seem to be a bit lazy to write an entire post about how I started my new project and basically rely on the language and service's documentation. But this particular documentation is so good and detailed, I don't see much benefit in me just rewriting it. And, if there's one piece of advice I would give a new engineer, it's that he or she should get comfortable reading and implementing from documentation. The next few parts of this project will be less &lt;em&gt;out of the box&lt;/em&gt;, influenced by multiple sources of inspiration, and have more written guidance.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/"&gt;https://hexdocs.pm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/overview.html"&gt;https://hexdocs.pm/phoenix/overview.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/installation.html"&gt;https://hexdocs.pm/phoenix/installation.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hexdocs.pm/phoenix/up_and_running.html#content"&gt;https://hexdocs.pm/phoenix/up_and_running.html#content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/git-guides/git-init"&gt;https://github.com/git-guides/git-init&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/new"&gt;https://github.com/new&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line"&gt;https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This post is part of an ongoing &lt;a href="https://dev.to/noelworden/new-side-project-new-blog-series-135h"&gt;series&lt;/a&gt;. I encourage any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>New Side Project, New Blog Series</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 23 Sep 2020 15:04:10 +0000</pubDate>
      <link>https://forem.com/noelworden/new-side-project-new-blog-series-135h</link>
      <guid>https://forem.com/noelworden/new-side-project-new-blog-series-135h</guid>
      <description>&lt;p&gt;I am currently in between projects at work, and I decided a good way to spend my time would be to spin up a side project. For nearly a year I have been compiling a dataset of my favorite GPS coordinates along with other attributes of the location, knowing that at some point, when I had the time, I could use it as a jumping off point for a project. There are some aspects of my recent work project I wanted to dig further into, as well as some things that didn't exist at all and I want to see what it would take to implement. The end goal of this project is more a sandbox to experiment with than a polished app. But, if at some point I get something that is worth sharing with the world, that would be great as well.&lt;/p&gt;

&lt;p&gt;As with my other blog series &lt;a href="https://dev.to/noelworden/beginning-of-a-blog-series-5aj3"&gt;This Week I Learned&lt;/a&gt;, I know that I learn a lot when I write about my process, so writing my way through this side project was an easy decision. In addition to expanding my knowledge, I hope that writing about my process can help someone else's process be a little bit smoother. &lt;/p&gt;

&lt;p&gt;This side project and the articles that accompany it are all about learning, as such, I would greatly appreciate any feedback on how I might improve on the code I implement. &lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>A Few Caveats to Running Elixir Tests in Containers and CI</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Thu, 17 Sep 2020 14:18:08 +0000</pubDate>
      <link>https://forem.com/noelworden/a-few-caveats-to-running-elixir-tests-in-containers-and-ci-21ef</link>
      <guid>https://forem.com/noelworden/a-few-caveats-to-running-elixir-tests-in-containers-and-ci-21ef</guid>
      <description>&lt;p&gt;As a fitting follow up to last week's &lt;a href="https://dev.to/noelworden/docker-connecting-an-elixir-phoenix-app-container-and-database-container-2n0a"&gt;post&lt;/a&gt; dealing with proper database configuration and Docker containers, this week I ran into a related snag while trying to get my tests to run in the app container. When I ran the &lt;code&gt;mix test&lt;/code&gt; command through &lt;code&gt;docker-compose&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose exec web mix test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It failed with the following error:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Although this wasn't the &lt;em&gt;exact&lt;/em&gt; same error from my previous experience, it's in a similar vein. I checked out the &lt;code&gt;test.exs&lt;/code&gt; configuration, and low and behold, in the Repo configuration I found:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I updated &lt;code&gt;hostname&lt;/code&gt; from &lt;code&gt;"localhost"&lt;/code&gt; to &lt;code&gt;"db"&lt;/code&gt; -the name of the database container- and re-ran:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose exec web mix test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It successfully compiled, ran the tests, and everything was good to go, or so I thought. After creation of the pull request the CI spun up a new check... and it failed. To my surprise, it was failing at the same step and showing the same error as I discussed in last weeks post, only this time instead of the error happening on my local machine, it was happening on the CI build:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;After changing the &lt;code&gt;test.exs&lt;/code&gt; configuration and pushing that up to the pull request to confirm, I concluded that the CI workflow needed the testing database &lt;code&gt;hostname&lt;/code&gt; to be &lt;code&gt;"localhost"&lt;/code&gt; while it &lt;em&gt;also&lt;/em&gt; needed to be &lt;code&gt;"db"&lt;/code&gt; for the tests to run in the app container.&lt;/p&gt;

&lt;p&gt;The solution I found for this utilized &lt;a href="https://hexdocs.pm/elixir/System.html#get_env/2"&gt;&lt;code&gt;System.get_env/1&lt;/code&gt;&lt;/a&gt;. I found a &lt;a href="https://github.com/actions/setup-elixir#authenticating-with-postgres-in-phoenix"&gt;post&lt;/a&gt; that shows how to set configurations based on environment variables. When the app is being run in the CI workflow, there is a &lt;code&gt;GITHUB_ACTION&lt;/code&gt; environmental variable set, so a conditional can be built around that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Placing that conditional under the initial configuration will override the line &lt;code&gt;hostname: "db"&lt;/code&gt; when the app is running in a CI workflow. The entire setup looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With that conditional set, the tests successfully run in the local app container using &lt;code&gt;"db"&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; in the CI workflow using &lt;code&gt;"localhost"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But there's more, a potential for refactoring! While researching and digging deeper into this, I came across a &lt;a href="https://dev.to/jonoyeong/how-to-setup-ci-with-phoenix-github-actions-4k68"&gt;post&lt;/a&gt; that utlized environment variables in a slightly different way, which I actually preferred and refactored my work to emulate. He suggested setting an environmental variable in the CI workflow file itself, then injecting that variable as a conditional in the original database configuration. My original &lt;code&gt;mix test&lt;/code&gt; command for the CI workflow was this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Adding an environmental variable looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now, in &lt;code&gt;test.exs&lt;/code&gt;, instead of that entire conditional &lt;em&gt;under&lt;/em&gt; the original configuration, the &lt;code&gt;hostname&lt;/code&gt; field can be set conditionally as a one-liner:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; that one-liner can be refactored &lt;em&gt;even further&lt;/em&gt;. Theres also a &lt;a href="https://hexdocs.pm/elixir/System.html#get_env/2"&gt;&lt;code&gt;System.get_env/2&lt;/code&gt;&lt;/a&gt; that allows for two arguments to be passed, the first is the environmental variable, and the second is a default value if that environmental variable cannot be found. So, instead of using &lt;code&gt;||&lt;/code&gt; to set the &lt;code&gt;hostname&lt;/code&gt; to &lt;code&gt;"db"&lt;/code&gt; if &lt;code&gt;System.get_env("DB_HOSTNAME")&lt;/code&gt; returns &lt;code&gt;nil&lt;/code&gt;, it can be all be done in the single function call:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With that refactor both testing environments run error free, and the codebase is just a touch cleaner. &lt;/p&gt;

&lt;p&gt;If you'd like to see the complete files, feel free to explore my public &lt;a href="https://github.com/noelworden/atlas/tree/e33a6f3e2b9f9eda2b2cc6f91a16e55a0367d593"&gt;repo&lt;/a&gt;, linked to the point where this was work was merged in. &lt;/p&gt;




&lt;p&gt;This post is part of an ongoing &lt;em&gt;This Week I Learned&lt;/em&gt; &lt;a href="https://dev.to/noelworden/beginning-of-a-blog-series-5aj3"&gt;series&lt;/a&gt;. I welcome any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>devops</category>
      <category>thisweekilearned</category>
    </item>
    <item>
      <title>Docker: Connecting an Elixir/Phoenix App Container and Database Container</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Wed, 09 Sep 2020 14:54:56 +0000</pubDate>
      <link>https://forem.com/noelworden/docker-connecting-an-elixir-phoenix-app-container-and-database-container-2n0a</link>
      <guid>https://forem.com/noelworden/docker-connecting-an-elixir-phoenix-app-container-and-database-container-2n0a</guid>
      <description>&lt;p&gt;While spinning up an Elixir/Phoenix side project I ended up being blocked for longer than I'd like to admit trying to get my app container and database containers to communicate with each other. The fix ended up to not having anything to do with the &lt;code&gt;Dockerfile&lt;/code&gt; or &lt;code&gt;docker-compose.yml&lt;/code&gt;, but in the &lt;code&gt;dev.exs&lt;/code&gt; config file.&lt;/p&gt;

&lt;p&gt;The default database configuration from the &lt;code&gt;phx.new&lt;/code&gt; generation looked like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Which works fine when running the app locally, without Docker. But, when starting the app and database containers in Docker, I would get the following error:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;What's happening is that the project container is looking for a database named &lt;code&gt;localhost&lt;/code&gt;, but the database is no longer running locally nor by the name &lt;code&gt;localhost&lt;/code&gt;. It is now running as a container by the name declared in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file. In my case I named it &lt;code&gt;db&lt;/code&gt;, so I needed to update the &lt;code&gt;hostname&lt;/code&gt; field of the database &lt;code&gt;config&lt;/code&gt; to this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that I have solved the problem, and know what to look for, I see that it is mentioned in the Docker &lt;a href="https://docs.docker.com/compose/networking/"&gt;docs&lt;/a&gt;. In hindsight I may have been too rabbit-holed in finding the solution to this problem in blog posts or step-by-steps that were specific to Elixir/Phoenix and Docker, although I am a bit surprised that this step was not mentioned in any of those sources. But, it is documented now, so hopefully I can help save someone else a a bit of time debugging their dockerized Elixir/Phoenix app.&lt;/p&gt;




&lt;p&gt;This post is part of an ongoing &lt;em&gt;This Week I Learned&lt;/em&gt; &lt;a href="https://dev.to/noelworden/beginning-of-a-blog-series-5aj3"&gt;series&lt;/a&gt;. I welcome any critique, feedback, or suggestions in the comments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>elixir</category>
      <category>thisweekilearned</category>
      <category>devops</category>
    </item>
    <item>
      <title>The F*ck - A Great Little Productivity App</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Tue, 01 Sep 2020 14:21:52 +0000</pubDate>
      <link>https://forem.com/noelworden/the-f-ck-a-great-little-productivity-app-5b0c</link>
      <guid>https://forem.com/noelworden/the-f-ck-a-great-little-productivity-app-5b0c</guid>
      <description>&lt;p&gt;Welp, things have been a bit slow on the project. The last few weeks have been a lot of rinse and repeat kind of stuff, but alas, that's how it goes sometimes. All that to say that there wasn't much in the way of &lt;em&gt;This Week I Learned&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, I do want to share what is probably my favorite productivity-related app: &lt;a href="https://github.com/nvbn/thefuck"&gt;The Fuck&lt;/a&gt;. Now is probably a good time to mention that the 'F Bomb' will be dropped a few more times in this post, but it's all in good fun, so I hope it's not too offensive. Now, what is &lt;em&gt;The Fuck&lt;/em&gt;, and why do I like it so much? From the docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Fuck is a magnificent app, inspired by a &lt;a href="https://twitter.com/liamosaur/"&gt;@liamosaur&lt;/a&gt; &lt;a href="https://twitter.com/liamosaur/status/506975850596536320"&gt;tweet&lt;/a&gt;, that corrects errors in previous console commands&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, basically, if you drop a typo in a command, say, like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git chekout develop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You would get a a nice error message from &lt;code&gt;git&lt;/code&gt;, even suggesting the correction. But instead of having to type it out again, you can simply type:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fuck&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And you are presented with what &lt;em&gt;The Fuck&lt;/em&gt; assumes you meant to type initially:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout develop [enter/↑/↓/ctrl+c]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;From there you can either hit &lt;code&gt;enter&lt;/code&gt; to use that suggested command, use the up/down arrows to cycle through the options, or &lt;code&gt;ctrl c&lt;/code&gt; to abort.&lt;/p&gt;

&lt;p&gt;But that is just one of the fairly large list of commands that &lt;em&gt;The Fuck&lt;/em&gt; recognizes and can fix, a comprehensive list can be found on the incredibly well documented &lt;a href="https://github.com/nvbn/thefuck#the-fuck-----"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Because the README is so detailed, I'm not going to retype all the intricacies here. I will say that the install is very simple:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;brew install thefuck&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And it is highly customizable. There is even an &lt;a href="https://github.com/nvbn/thefuck#experimental-instant-mode"&gt;experimental instant mode&lt;/a&gt;, if that's your cup of tea.&lt;/p&gt;

&lt;p&gt;This little app gets me to chuckle out loud just about every time I use it. It's kind of perfect, since I have been known to swear under my breath when frustrated, now I can take that energy and actually fix the problem! And, if you are someone who isn't a fan of typing out the 'F word' on the regular, you could always utilize this powerful tool from an alias, like, I dunno, &lt;code&gt;duck&lt;/code&gt;?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>thisweekilearned</category>
    </item>
    <item>
      <title>PSA: Take Some Time for Yourself</title>
      <dc:creator>Noel Worden</dc:creator>
      <pubDate>Tue, 25 Aug 2020 18:54:43 +0000</pubDate>
      <link>https://forem.com/noelworden/psa-take-some-time-for-yourself-ehb</link>
      <guid>https://forem.com/noelworden/psa-take-some-time-for-yourself-ehb</guid>
      <description>&lt;p&gt;I was on PTO most of last week, so I don't have much of a This Week I Learned kind of thing. But, since I'm trying to write every week I thought it would be worthwhile to type out a friendly reminder: &lt;/p&gt;

&lt;h5&gt;
  
  
  take time for yourself
&lt;/h5&gt;

&lt;p&gt;My supervisor said it best, "you're not working from home, you're living at work". Whether it is during the regular work day, or during a side project, remember that it's ok to take a break. Go for a stroll around the block, around the neighborhood, or until your feet are sore!&lt;/p&gt;

&lt;p&gt;I promise you will be happier &lt;em&gt;and&lt;/em&gt; more productive after you allow yourself some time to breath.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
  </channel>
</rss>
