<?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>DEV Community: Andreas Frömer</title>
    <description>The latest articles on DEV Community by Andreas Frömer (@icanhazstring).</description>
    <link>https://dev.to/icanhazstring</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%2F168561%2F7fa818fe-4a7f-4b23-bb95-5258a8da17d7.jpeg</url>
      <title>DEV Community: Andreas Frömer</title>
      <link>https://dev.to/icanhazstring</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/icanhazstring"/>
    <language>en</language>
    <item>
      <title>Using monorepo-builder outside of github and gitlab</title>
      <dc:creator>Andreas Frömer</dc:creator>
      <pubDate>Mon, 16 May 2022 08:07:19 +0000</pubDate>
      <link>https://dev.to/icanhazstring/using-monorepo-builder-outside-of-github-and-gitlab-5gk2</link>
      <guid>https://dev.to/icanhazstring/using-monorepo-builder-outside-of-github-and-gitlab-5gk2</guid>
      <description>&lt;p&gt;At work we are managing multiple repositories. Also repositories where the context is exactly the same. For example: We are developing an application providing multiple endpoint to our clients. We also developing an api-sdk for our clients to communicate with our apis.&lt;/p&gt;

&lt;p&gt;Right now, this is all done in two separate repositories.&lt;br&gt;
Which is absolutely fine. But I kind of don't like it anymore.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem with separate repositories for a single context
&lt;/h2&gt;

&lt;p&gt;What happens if you change an API and you have to adjust the contract for it?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clone API-SDK repository&lt;/li&gt;
&lt;li&gt;clone API&lt;/li&gt;
&lt;li&gt;make changes to your API&lt;/li&gt;
&lt;li&gt;make changes to your API-SDK&lt;/li&gt;
&lt;li&gt;require dev-branch (or local link) from API-SDK into API&lt;/li&gt;
&lt;li&gt;write tests for your API with the changed contract&lt;/li&gt;
&lt;li&gt;tag API-SDK with new version&lt;/li&gt;
&lt;li&gt;release API changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, these are a lot of steps you have to do while working with the API.&lt;/p&gt;

&lt;p&gt;So, what can we do about it?&lt;/p&gt;
&lt;h2&gt;
  
  
  Monorepo to the rescue
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't know what a monorepo is, or why you should care about. Check out the blog post from &lt;a class="mentioned-user" href="https://dev.to/tomasvotruba"&gt;@tomasvotruba&lt;/a&gt; &lt;a href="https://tomasvotruba.com/blog/2019/10/28/all-you-always-wanted-to-know-about-monorepo-but-were-afraid-to-ask"&gt;All You Always Wanted to Know About Monorepo But Were Afraid To Ask&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adding the SDK into the repository of the API makes thing easier than ever. You can now work directly on the SDK in the latest version, write your tests immediately from inside your API.&lt;/p&gt;

&lt;p&gt;If everything works, just tag it and publish your package.&lt;/p&gt;

&lt;p&gt;Easy right? Right?&lt;/p&gt;
&lt;h2&gt;
  
  
  How to publish packages from your monorepo
&lt;/h2&gt;

&lt;p&gt;When it comes to the part of actually publishing packages from inside your monorepo you have to get creative with a lot of git commands, or other existing tools like &lt;a href="https://github.com/symplify/monorepo-builder"&gt;symplify/monorepo-builder&lt;/a&gt; from &lt;a class="mentioned-user" href="https://dev.to/tomasvotruba"&gt;@tomasvotruba&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In the latest version, he added the support for github and gitlab, so you can just include this as a &lt;a href="https://github.com/symplify/monorepo-split-github-action"&gt;workflow action&lt;/a&gt; and you are done for. This is awesome! &lt;/p&gt;

&lt;p&gt;There is a but! Using the github action in my company was not a real option since we are using an on-site bitbucket server. Damn it!&lt;/p&gt;

&lt;p&gt;Gone are the dreams of easy monorepo splitting :(&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker to the rescue
&lt;/h2&gt;

&lt;p&gt;If you don't know, Github actions is working with docker in the background. So, actually I could just use the docker image and run it myself, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yes I Can!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But what about the direct reference to Github and Gitlab for the splitter?&lt;/p&gt;

&lt;p&gt;Well, lucky for us, we can just set some environment variables from bitbucket and everything works as expected :)&lt;/p&gt;

&lt;p&gt;The only "hack" we need to do, is to set the &lt;code&gt;GITLAB_CI=bitbucket&lt;/code&gt; environment so that we don't need to deal with the &lt;a href="https://github.com/symplify/monorepo-split-github-action/blob/main/src/ConfigFactory.php#L64"&gt;prefix&lt;/a&gt; &lt;code&gt;INPUT_&lt;/code&gt; from Github.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running the docker image
&lt;/h2&gt;

&lt;p&gt;So how can I run the splitter using docker?&lt;br&gt;
Well, here is a little bash script to do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run \
  -e GITLAB_CI=bitbucket \
  -e PAT="user:accesstoken" \
  -e PACKAGE_DIRECTORY=packages/test-package \
  -e REPOSITORY_ORGANIZATION=org \
  -e REPOSITORY_NAME=test-package \
  -e BRANCH=master \
  -e REPOSITORY_HOST=bitbucket.host.de/scm \
  -e CI_COMMIT_SHA=$COMMIT_SHA \
  -e USER_NAME="User Name" \
  -e USER_EMAIL=user.name@email.de \
  -e TAG=$TAG \
  --workdir=/bitbucket/workspace \
  -v $(pwd):"/bitbucket/workspace" \
  --rm \
  symplify2/monorepo-split:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gitlab allows the login using only accesstoken. But we can just pass the &lt;code&gt;username:accesstoken&lt;/code&gt; as &lt;code&gt;PAT&lt;/code&gt; for the splitter.&lt;/p&gt;

&lt;p&gt;Also the &lt;code&gt;REPOSITORY_HOST&lt;/code&gt; is not only the host, but contains also a part of the basepath to the repositories.&lt;/p&gt;

&lt;p&gt;One important change is the &lt;code&gt;--workdir&lt;/code&gt; and &lt;code&gt;-v&lt;/code&gt; option. The workdir has to be set, as we need our sources inside the running container and the can't override the sources from the splitter itself. So we need another folder where we link our current working directory into it.&lt;/p&gt;




&lt;p&gt;And thats it. It works perfectly :)&lt;br&gt;
Thanks &lt;a class="mentioned-user" href="https://dev.to/tomasvotruba"&gt;@tomasvotruba&lt;/a&gt; for this amazing tool &amp;lt;3 &lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>monorepo</category>
      <category>composer</category>
    </item>
    <item>
      <title>Delay between retries for Supervisor</title>
      <dc:creator>Andreas Frömer</dc:creator>
      <pubDate>Thu, 04 Nov 2021 13:36:13 +0000</pubDate>
      <link>https://dev.to/icanhazstring/delay-between-retries-for-supervisor-47gm</link>
      <guid>https://dev.to/icanhazstring/delay-between-retries-for-supervisor-47gm</guid>
      <description>&lt;p&gt;Having process managing tools on current systems is a must have. The most common used, or at least the tools I have been using, are &lt;code&gt;systemd&lt;/code&gt; and &lt;code&gt;supervisor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While both do basically the same, &lt;code&gt;supervisor&lt;/code&gt; is lacking one crucial ability: &lt;em&gt;The ability to have a delay between process restarts&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While this is not always necessary, in some cases it will prevent your process to get into &lt;code&gt;FATAL&lt;/code&gt; state which stops it altogether.&lt;/p&gt;

&lt;p&gt;But why isn't there such an option?&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution already exists
&lt;/h2&gt;

&lt;p&gt;The problems is not that it is impossible to add such a feature, but rather that the maintainers need to merge and maintain it.&lt;/p&gt;

&lt;p&gt;There already exists a &lt;a href="https://github.com/Supervisor/supervisor/issues/487"&gt;feature request from 2014&lt;/a&gt; and the solving &lt;a href="https://github.com/Supervisor/supervisor/pull/659"&gt;pull request from 2015&lt;/a&gt; which, to this time of writing, haven't been merged.&lt;/p&gt;

&lt;p&gt;I have to make clear: I am not blaming the maintainers for not merging it. It is simply a matter of time from the maintainers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can you still add a delay
&lt;/h2&gt;

&lt;p&gt;To still add a delay you need to get somewhat creative.&lt;br&gt;
While searching for a solution I found the feature request for supervisor (see above), this mentions a solution to use a &lt;code&gt;sleep X&lt;/code&gt; after your &lt;code&gt;command&lt;/code&gt; for your supervisor process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[program:www]
command=bash -c "&amp;lt;path to your script&amp;gt;; sleep X"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this might work, the problem is that supervisor can not gracefully stop this process using a &lt;code&gt;SIGTERM&lt;/code&gt; signal. The &lt;code&gt;SIGTERM&lt;/code&gt; will only hit your &lt;code&gt;bash&lt;/code&gt; command, but not your actual script.&lt;/p&gt;

&lt;p&gt;So what can you do?&lt;br&gt;
While reading further into the feature request if found a pull request to &lt;code&gt;symfony/messenger&lt;/code&gt; component, here the author added a script which actually is capable forwarding the &lt;code&gt;SIGTERM&lt;/code&gt; signal into the child process.&lt;/p&gt;

&lt;p&gt;You can find the PR here: &lt;a href="https://github.com/symfony/symfony-docs/pull/13597"&gt;https://github.com/symfony/symfony-docs/pull/13597&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Extracted from this PR, the scripts looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Supervisor sends TERM to services when stopped.&lt;/span&gt;
&lt;span class="c"&gt;# This wrapper has to pass the signal to it's child.&lt;/span&gt;
&lt;span class="c"&gt;# Note that we send TERM (graceful) instead of KILL (immediate).&lt;/span&gt;
_term&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="nt"&gt;-TERM&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$child&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;trap &lt;/span&gt;_term SIGTERM

&lt;span class="c"&gt;# Execute console.php with whatever arguments were specified to this script&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;
&lt;span class="nv"&gt;child&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$child&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="c"&gt;# Delay to prevent supervisor from restarting too fast on failure&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;30

&lt;span class="c"&gt;# Return with the exit code of the wrapped process&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$rc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the "only" thing you need to change is to prepend this wrapper in front to you previous command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[program:www]
/path/to/wrapper &amp;lt;path to your script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way every &lt;code&gt;SIGTERM&lt;/code&gt; will passed into your script and will exit as soon as the child is terminated. If you child process will die with some exit code larger 0, it will sleep for 30 seconds before exiting. After that period, supervisor will restart it again.&lt;/p&gt;




&lt;p&gt;Credits goes to the authors of both pull requests as they have done the work already. I am just a messenger :)&lt;/p&gt;

</description>
      <category>supervisor</category>
      <category>delay</category>
      <category>unix</category>
      <category>programming</category>
    </item>
    <item>
      <title>Making a string shorter without losing its meaning</title>
      <dc:creator>Andreas Frömer</dc:creator>
      <pubDate>Fri, 10 Jul 2020 14:12:47 +0000</pubDate>
      <link>https://dev.to/icanhazstring/making-a-string-shorter-without-losing-its-meaning-4gkm</link>
      <guid>https://dev.to/icanhazstring/making-a-string-shorter-without-losing-its-meaning-4gkm</guid>
      <description>&lt;p&gt;Today I was confronted with a small but meaningful problem writing some piece of software. I reached some kind of threshold where the string does not fit, so I would have to shorten it. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I could remove all characters of each word keeping only the first three&lt;/li&gt;
&lt;li&gt;Remove all vowels&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But how do I make sure to keep the meaning of the string so you could still understand what's written 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  Small overview
&lt;/h2&gt;

&lt;p&gt;To give you a small outline of what I was doing - I am importing huge amounts of data of unknown structure. So I am doing a scan over all data sets trying to figure out the structure, flatten it, and use it as MySQL column names.&lt;/p&gt;

&lt;p&gt;Here is an example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "payload":{
      "product":{
         "details":{
            "aru":{
               "children":[
                  {
                     "aru":{
                        "products":[
                           {
                              "aru":{
                                 "street":"",
                                 "streetnumber":"",
                                 "productKey":"",
                                 "price":"",
                                 "tariffName":"",
                                 "insurancePolicyNumber":""
                              }
                           }
                        ]
                     }
                  }
               ]
            }
         }
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might already see an upcoming problem here 😉&lt;br&gt;
And don't ask about the structure - it is what it is.&lt;/p&gt;
&lt;h2&gt;
  
  
  The limitations
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;innodb&lt;/code&gt; the limitation for column names is 64 characters. At first glance, and with multiple scans, this was going to be close to maximum but still worked.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hence comes the problem
&lt;/h2&gt;

&lt;p&gt;Of course, the limitations were reached while going into production as there was new data coming which exceeded it.&lt;/p&gt;

&lt;p&gt;I am now presented with a string of 69 characters of length. Knowing that there will be a string coming exceeding it even further there needed to be some kind of reduction in characters.&lt;/p&gt;
&lt;h2&gt;
  
  
  Possible solutions
&lt;/h2&gt;

&lt;p&gt;Given the following strings here are some solutions I have considered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payloadProductDetailsAruChildren3AruProducts0AruStreet
payloadProductDetailsAruChildren3AruProducts0AruStreetnumber
payloadProductDetailsAruChildren3AruProducts0AruProductKey           
payloadProductDetailsAruChildren3AruProducts0AruPrice                
payloadProductDetailsAruChildren3AruProducts0AruTariffName           
payloadProductDetailsAruChildren3AruProducts0AruInsurancePolicyNumber
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Only keep first 3 characters
&lt;/h3&gt;

&lt;p&gt;Shortening the string by keeping the first 3 characters was the first and a very fast solution. Which ended in not even a solution but making it even worse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payProDetAruChi3AruPro0AruStr
payProDetAruChi3AruPro0AruStr
payProDetAruChi3AruPro0AruProKey           
payProDetAruChi3AruPro0AruPri                
payProDetAruChi3AruPro0AruTarNam           
payProDetAruChi3AruPro0AruInsPolNum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see the problem, we ended up with two equal column names which would be a disaster since we would be losing data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove all vowels
&lt;/h3&gt;

&lt;p&gt;A colleague of mine came up with the idea of removing all lower case vowels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyldPrdctDtlsArChldrn3ArPrdcts0ArStrt
pyldPrdctDtlsArChldrn3ArPrdcts0ArStrtnmbr
pyldPrdctDtlsArChldrn3ArPrdcts0ArPrdctKy           
pyldPrdctDtlsArChldrn3ArPrdcts0ArPrc                
pyldPrdctDtlsArChldrn3ArPrdcts0ArTrffNm           
pyldPrdctDtlsArChldrn3ArPrdcts0ArInsrncPlcyNmbr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which looks better and we don't have a conflicting column name. But still, some column names seem hard to read. For example &lt;code&gt;pyldPrdctDtlsArChldrn3ArPrdcts0ArPrc&lt;/code&gt;. Thinking of &lt;code&gt;Price&lt;/code&gt; at the end is hard to nearly impossible.&lt;/p&gt;

&lt;p&gt;Also, the product name &lt;code&gt;Aru&lt;/code&gt; is shortened. That is not a big problem but still 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  The Significance of Letter Position in Word Recognition
&lt;/h2&gt;

&lt;p&gt;This is the title of a Ph.D. thesis written by Graham Rawlinson back in 1979. &lt;/p&gt;

&lt;p&gt;In a short summary: Every word having the &lt;strong&gt;first&lt;/strong&gt; and &lt;strong&gt;last&lt;/strong&gt; character in place might miss or have shuffled characters in between and you might still understand the word.&lt;/p&gt;

&lt;p&gt;With this in mind, I improved the "vowel solution" to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only remove lowercase vowels which are not followed by an uppercase character or beginning or end of the string.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The final solution
&lt;/h2&gt;

&lt;p&gt;Using regex substitution I shortened the string so that it should be understandable for someone working in the same field.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(?&amp;lt;!^)[aeiou](?!([A-Z]|$))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The result is better understandable and still with no naming conflicts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyldPrdctDtlsAruChldrn3AruPrdcts0AruStrt
pyldPrdctDtlsAruChldrn3AruPrdcts0AruStrtnmbr
pyldPrdctDtlsAruChldrn3AruPrdcts0AruPrdctKy           
pyldPrdctDtlsAruChldrn3AruPrdcts0AruPrce                
pyldPrdctDtlsAruChldrn3AruPrdcts0AruTrffNme           
pyldPrdctDtlsAruChldrn3AruPrdcts0AruInsrncePlcyNmbr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is still the possibility to end up with identical consonants after removing the vowels. But this is considered a lower probability then simply removing all vowels.&lt;/p&gt;

&lt;p&gt;One word could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Color =&amp;gt; Clr
Clear =&amp;gt; Clr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;If you liked the article leave me a comment/like. Do you have any other suggestions? Let me know!&lt;/p&gt;

&lt;p&gt;You can follow me on twitter with &lt;a href="https://twitter.com/icanhazstring"&gt;@icanhazstring&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Update: 2020-07-14&lt;br&gt;
Changed the final solution regular expression to avoid removing lowercase vowels at the beginning of the string&lt;/p&gt;

</description>
      <category>php</category>
      <category>database</category>
      <category>language</category>
    </item>
    <item>
      <title>Add a required argument to every symfony/console command</title>
      <dc:creator>Andreas Frömer</dc:creator>
      <pubDate>Wed, 03 Jun 2020 13:44:40 +0000</pubDate>
      <link>https://dev.to/icanhazstring/add-a-required-argument-to-every-symfony-console-command-4b7a</link>
      <guid>https://dev.to/icanhazstring/add-a-required-argument-to-every-symfony-console-command-4b7a</guid>
      <description>&lt;p&gt;I would assume that everyone has fiddled around with &lt;code&gt;symfony/console&lt;/code&gt; right? If not, you should probably check it out &lt;a href="https://symfony.com/doc/current/components/console.html"&gt;here&lt;/a&gt;. It is pretty easy to use and understand.&lt;/p&gt;

&lt;p&gt;One thing I had problems today is: How do you add a &lt;strong&gt;required&lt;/strong&gt; argument for every command that is added to the console application?&lt;/p&gt;

&lt;p&gt;I came up with 3 solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adding a &lt;code&gt;BaseCommand&lt;/code&gt; class which every command added has to &lt;code&gt;extend&lt;/code&gt; from&lt;/li&gt;
&lt;li&gt;Add a required argument to the &lt;code&gt;Console\Application&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a required argument for each &lt;code&gt;Console\Command&lt;/code&gt; added to the &lt;code&gt;Console\Application&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;p&gt;Like President Schwarzenegger used to say in the Simpson Movie: "I pick number three".&lt;br&gt;
This way for me is most robust change as you don't need to alter any command and every new command that will be added, will receive the required argument.&lt;/p&gt;

&lt;p&gt;Just as a side note: I used to pick the first approach :)&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a &lt;code&gt;BaseCommand&lt;/code&gt; class which every command added has to &lt;code&gt;extend&lt;/code&gt; from
&lt;/h2&gt;

&lt;p&gt;This is pretty straight forward. You create a new &lt;code&gt;BaseCommand&lt;/code&gt; class and add your required argument into the &lt;code&gt;configure()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Console\Command\Command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseCommand&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;addArgument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;InputArgument&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'description'&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, what this would require is you &lt;strong&gt;have&lt;/strong&gt; to call &lt;code&gt;parent::configure()&lt;/code&gt; in every command so that the argument is there, if not. Well its not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a required argument to the &lt;code&gt;Console\Application&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This was the second approach I found while searching for a solution.&lt;br&gt;
Sadly, every solution I found was adding a new &lt;strong&gt;optional&lt;/strong&gt; argument to the definition, which is not what I needed, you might need to "fiddle" around with the &lt;code&gt;setArguments()&lt;/code&gt; of the &lt;code&gt;InputDefinition&lt;/code&gt; of an application.&lt;/p&gt;

&lt;p&gt;You can do this inside you bootstrap file, whery you load the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$appDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$app&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getDefinition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$appDefininition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$requiredArgument&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$appDefinition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getArguments&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is kind of out of scope where you want to define it.&lt;br&gt;
So you can create your custom application class and do it there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Console\Application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Console\Input\InputDefinition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomApplication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getDefaultInputDefinition&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;InputDefinition&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getDefaultInputDefinition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$definition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$requiredArgument&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$definition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getArguments&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="nv"&gt;$definition&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Downside on this: You have a require argument for every command of your application even with the &lt;code&gt;HelpCommand&lt;/code&gt; or &lt;code&gt;ListCommand&lt;/code&gt;. So you can't run you application by simply running &lt;code&gt;bin/console&lt;/code&gt; (if that is you entrypoint). You would need to pass the required argument everytime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a required argument for each &lt;code&gt;Console\Command&lt;/code&gt; added to the &lt;code&gt;Console\Application&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The solution I choose, was to add this argument for each command added to the application.&lt;/p&gt;

&lt;p&gt;Some of you might think: Wait a second, what abount &lt;code&gt;HelpCommand&lt;/code&gt; and &lt;code&gt;ListCommand&lt;/code&gt; you mentioned before?&lt;/p&gt;

&lt;p&gt;Yes you are right, every command, except commands from &lt;code&gt;symfony/console&lt;/code&gt; namespace :)&lt;/p&gt;

&lt;p&gt;So this is my solution: Creating my &lt;code&gt;CustomApplication&lt;/code&gt; and overwriting the &lt;code&gt;add(Command $command)&lt;/code&gt; adding my required argument to every added command to my application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Console\Application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Component\Console\Command\Command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConsoleApplication&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="nv"&gt;$command&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="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;strpos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;get_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'Symfony\Component\Console'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&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="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$commandDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getDefinition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$commandDefinition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$requiredArgument&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$commandDefinition&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getArguments&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="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$command&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it. Every command will get your required argument. Also this will be the first argument in every command. So even if you have an optional argument configured, there won't be a problem with that.&lt;/p&gt;




&lt;p&gt;Hope that will help some of you solving the same problem I had :)&lt;br&gt;
If you have another clever solution, let me know!&lt;/p&gt;

</description>
      <category>symfony</category>
      <category>console</category>
      <category>argument</category>
      <category>required</category>
    </item>
    <item>
      <title>Local testing for GitHub Actions (on MacOS)</title>
      <dc:creator>Andreas Frömer</dc:creator>
      <pubDate>Sat, 23 May 2020 07:31:03 +0000</pubDate>
      <link>https://dev.to/icanhazstring/local-testing-for-github-actions-on-macos-4lob</link>
      <guid>https://dev.to/icanhazstring/local-testing-for-github-actions-on-macos-4lob</guid>
      <description>&lt;h2&gt;
  
  
  The beginnings
&lt;/h2&gt;

&lt;p&gt;Back in October 2018, when GitHub Actions were announced, things got pretty serious pretty fast. Everyone was jumping on the train and were replacing their old CI/CD integration with the new workflow GitHub now provided.&lt;/p&gt;

&lt;p&gt;From my memory, the development of these workflows was a bit painful to say the least. You would have to add the changes to your workflow into your repository, push them and wait for the actions to complete.&lt;/p&gt;

&lt;p&gt;Hopefully.&lt;/p&gt;

&lt;p&gt;If not, do it again until everything worked out. The only thing I had done this far was a simple checkout, running some tests and that was pretty much it. Nothing fancy going one there.&lt;/p&gt;

&lt;p&gt;Recently I was reminded by &lt;a href="https://twitter.com/localheinz" rel="noopener noreferrer"&gt;@localheinz&lt;/a&gt; in a &lt;a href="https://twitter.com/localheinz/status/1261627962006351872" rel="noopener noreferrer"&gt;tweet&lt;/a&gt; that some of the actions for GitHub made a huge improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Later today
&lt;/h2&gt;

&lt;p&gt;Now one and a half years later having an actively used repository wit &lt;a href="https://github.com/composer-unused/composer-unused" rel="noopener noreferrer"&gt;composer-unused&lt;/a&gt;, I decided to check things again and improve the workflows. But - the testing. There has to be a way to test your workflow on your local machine. Right?&lt;/p&gt;

&lt;p&gt;Yes there is! &lt;a href="https://github.com/nektos/act" rel="noopener noreferrer"&gt;nektos/act&lt;/a&gt; to the rescue. &lt;/p&gt;

&lt;p&gt;This tool, written in Go, is pretty easy to install and navigate. I will give you a small overview how to install and run it on MacOS (other OS are also supported, see the &lt;a href="https://github.com/nektos/act#installation" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the tool running
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;nektos/act&lt;/code&gt; is using Docker to run your workflow on your machine. So first things first: &lt;strong&gt;setting up Docker&lt;/strong&gt; using homebrew&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ brew install docker docker-machine


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

&lt;/div&gt;

&lt;p&gt;You will also need to install a provider for Docker. For this example we are using &lt;code&gt;Virtualbox&lt;/code&gt;. You can install it a Homebrew Cask recipe:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ brew cask install virtualbox
-&amp;gt; password


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

&lt;/div&gt;

&lt;p&gt;You might see the following message when installing Virtualbox:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg0ikm4tizqslf9w5nwen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg0ikm4tizqslf9w5nwen.png" alt="virtual box security"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to head over into the settings and accept the software installation from &lt;code&gt;Oracle America Inc.&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwqiub8u4arso4ye3rz3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwqiub8u4arso4ye3rz3z.png" alt="security setting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next up, set up the default &lt;code&gt;docker-machine&lt;/code&gt; with &lt;code&gt;virtualbox&lt;/code&gt; driver and start it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ docker-machine create --driver virtualbox default
$ eval "$(docker-machine env default)"


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Install nektos/act
&lt;/h3&gt;

&lt;p&gt;Installation instruction taken from the &lt;a href="https://github.com/nektos/act#installation" rel="noopener noreferrer"&gt;docs&lt;/a&gt; using homebrew:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ brew install nektos/tap/act


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Run your workflow
&lt;/h3&gt;

&lt;p&gt;To run your workflow on your machine, just navigate to your repository folder and run.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ act


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

&lt;/div&gt;

&lt;p&gt;This will run your default job inside your workflow. Thats it!&lt;/p&gt;

&lt;p&gt;But wait! Thats all in the docs, so why this post?&lt;br&gt;
Well - I encountered a problem along the way:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

::error::ENOENT: no such file or directory, open '/opt/hostedtoolcache/linux.sh'


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Solving the issue
&lt;/h2&gt;

&lt;p&gt;The problem above has nothing to do with &lt;code&gt;nektos/act&lt;/code&gt; itself. But rather with the default Docker image it uses. To solve this, you can run &lt;code&gt;act -P &amp;lt;docker-image&amp;gt;&lt;/code&gt; to use another default image. &lt;/p&gt;

&lt;p&gt;Turns out &lt;a href="https://github.com/shivammathur/setup-php#local-testing-setup" rel="noopener noreferrer"&gt;shivammathur/setup-php&lt;/a&gt; was the solution.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ act -P ubuntu-latest=shivammathur/node:latest


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

&lt;/div&gt;

&lt;p&gt;But typing this command all over again is - well - annoying.&lt;/p&gt;

&lt;p&gt;To improve this, you can create a &lt;code&gt;~/.actrc&lt;/code&gt; file and put the command line arguments there so you only have to run &lt;code&gt;act&lt;/code&gt; inside your repository.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// ~/.actrc
-P ubuntu-latest=shivammathur/node:latest


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

&lt;/div&gt;

&lt;p&gt;Now everything is working as expected and I can improve my workflow to my needs while testing it locally on my machine first!&lt;/p&gt;




&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;nektos/act&lt;/code&gt; is a little over a year old now, so there are still some problems with certain workflows and OS setups. I have only encountered the problem mentioned above.&lt;/p&gt;

&lt;p&gt;If you encounter any other problem, don't hesitate and head over to the &lt;a href="https://github.com/nektos/act/issues" rel="noopener noreferrer"&gt;issue tracker&lt;/a&gt; of &lt;code&gt;nektos/act&lt;/code&gt; and describe your problem. This way we all can improve this awesome tool even further!&lt;/p&gt;

</description>
      <category>github</category>
      <category>testing</category>
      <category>actions</category>
      <category>local</category>
    </item>
  </channel>
</rss>
