├── README.md ├── intro-ru.md ├── intro.md ├── modern-make-handbook-ru.md └── modern-make-handbook.md /README.md: -------------------------------------------------------------------------------- 1 | ![](https://imgur.com/OubxVn4.png) 2 | 3 | # Modern Make handbook (v 0.6) 4 | [Handbook about Modern Make usage](http://makefile.site) 5 | 6 | ## How to contribute 7 | 8 | 1. If you found a typo or mistake in some code, please create an issue or pull request. 9 | 2. Feel free to create issue if you think that something must be added to the handbook. 10 | 3. If you want to suggest a translation, create a pull request with `modern-make-handbook-your_language.md` file 11 | 12 | ## 🎉Special thanks to: 13 | 14 | 1. [Andrew Slotin](https://github.com/andrewslotin) - for the first version of English translation 15 | -------------------------------------------------------------------------------- /intro-ru.md: -------------------------------------------------------------------------------- 1 | Make позволяет нарулить себе **библиотеку команд-шорткатов**, которые будут отражать семантику происходящего, а не реализацию: 2 | 3 | `make deploy`, `make logs`, `make feature resubscription` 4 | 5 | Makefile хранится в основном репозитории вместе с кодом и становится **живой документацией** по частоиспользуемым при разработке командам. 6 | 7 | 8 | – *О, камон, Make - это же что-то очень древнее! Где ты это выкопал вообще?* 9 | – *Я помню два года назад что-то собирал из сорцов мэйком. Разве он годится для чего-то еще?* 10 | – *Слушай, я же не на сях пишу чтобы что-то там билдить. У меня уже есть **npm/rake/maven**, какой мне еще мэйк?* 11 | 12 | Примерно так я думал, пока не разобрался в вопросе. 13 | 14 | По факту ==Make== – это такой **универсальный клей** между кучей технологий используемых в современной разработке. У него минимальный оверхед по сравнению со специфичными для языков инструментами. 15 | 16 | Голосование в твиттере доказывает что с вероятностью в 75% вы не используете Makefile в своих проектах: 17 | 18 | Если это так, значит что у вас сейчас есть возможность потратив пару часов, сэкономить себе в будущем гораздо больше времени. 19 | 20 | 21 | Сейчас для меня ==Make== стоит в одном ряду с Ansible, Docker и GitLab CI. 22 | Это добротный универсальный, по-хорошему хипстерский инструмент для упорядочивания хаоса в рабочих скриптах на проекте. 23 | 24 | Make всем хорош, но его официальная документация чересчур подробна, и, видимо, рассчитана на сисадминов-сишников, думающих на bash. Пробиться через неё без специальной подготовки нереально – слишком много специфики и деталей далеких от нужд современного разраба. 25 | 26 | Поэтому я запилил мини-руководство по полезным для современного разраба фишкам Make. Получилось так: 27 | 28 | 7500 строк → 500 строк 29 | 30 | На самом деле вам не нужно читать и их :) 31 | 32 | 33 | Как же так? 34 | Что же делать? 35 | 36 | 1. Чтобы **понять основную идею** использования Make и базовые правила, посмотрите [ролик от Хекслета](#intro) ▶️ (*8.5 минут на полуторной скорости*). 37 | 38 | 2. Если решили **применить Make на практике**, то вам пригодится [дока по основным фишкам и особенностям настройки Makefile](#handbook). 39 | 40 | 3. Если в стремлении навести порядок вы решили **идти до конца**, то для вас есть [расширенная версия](#soryan) с примером построения цельного workflow для dev/staging/production-окружений. 41 | 42 | 43 | Руководство по современному ==Make== 44 | 45 | 1. Making your library of shortcuts 46 | 2. Overcoming Make weirdness 47 | 3. Multiple commands at once 48 | 4. Subcommands 49 | 5. Aliases 50 | 6. Multiline commands 51 | 7. Suppressing output 52 | 8. Conditional execution 53 | 9. Passing arguments 54 | 55 | 10. Advanced scripting== 56 | 11. Putting things in order== 57 | 12. Naming conventions== 58 | 13. Full workflow automation== 59 | 14. Guiding principles== 60 | 61 | *Жмите на специальную [ссылку для самых умных](#too-smart) ;)* 62 | 63 | 64 | 65 | ## 💌Сорян! 66 | 67 | Полная версия еще не готова. 68 | Подпишитесь, и пришлю вам письмо, как только так сразу: 69 | 70 | 71 | -------------------------------------------------------------------------------- /intro.md: -------------------------------------------------------------------------------- 1 | 2 | With ==Make== you can establish a library of shortcuts for frequently used commands. Names of such shortcuts represent their semantics, not implementation: 3 | 4 | `make deploy`, `make logs`, `make feature resubscription` 5 | 6 | Makefile is stored in the project repository and becomes a live development workflow documentation shared between the whole team. 7 | 8 | - Hey, come on! Make is some ancient tool from the past! 9 | 10 | - I remember I used it to compile some libraries from sources two years ago? It can be used for something else? 11 | 12 | - Hold on, I am not a C/C++ developer to compile stuff. I already use npm/rake/maven. Why should I care about one more tool? 13 | 14 | This is how I thought too. The reality is that: 15 | 16 | 1. ==Make== plays the role of the universal glue between many technologies we have to use in the modern (web-)development. 17 | 2. It is not a replacement for your native tools for building and compiling stuff. 18 | 3. It is a way to take out all the shell scripts from your yarn/rake/maven because they look unnatural there and cause a lot of overhead 19 | 20 | Less than 25% of developers use Makefile as a library of shortcuts: 21 | 22 | [pic] 23 | 24 | If your one of the rest 75%, you're about to learn the approach, which can save you a huge amount of time in the future. 25 | 26 | Make is good, but its official documentation is too detailed and only readable if you're sysadmin thinking in a mix of C and shell scripts. It contains way too many details - way too far from the needs of a modern developer. 27 | 28 | Because of that, I created the mini-reference describing only features useful for modern developers. 29 | 30 | 7500 lines → 500 lines 31 | 32 | But you don't need to read them. 33 | 34 | How so? What should I do then? 35 | 36 | 1. To understand the main of modern Make usage, watch this 5 minutes video. 37 | 2. If you want to try it, download the Make mini-reference for modern developers. 38 | 3. If you want to organize the whole development workflow using Make, then an extended version of the reference with examples and advanced tricks is what you need. 39 | -------------------------------------------------------------------------------- /modern-make-handbook-ru.md: -------------------------------------------------------------------------------- 1 | # Modern Make Handbook (v. 0.6-ru) 2 | 3 | [![](https://i.imgur.com/a1MOR8T.png)](https://makefile.site) 4 | 5 | 6 | 7 | 8 | [TOC] 9 | 10 | 11 |
12 | ## 1. Making your library of shortcuts 13 | 14 | – Что говорит кошка, когда хочет кушать? 15 | 16 | – Мяу! 17 | 18 | 19 | 20 | – Что говорит собака, когда чует опасность? 21 | 22 | – Гав-гав! 23 | 24 | 25 | 26 | – А что говорит Вова когда хочет задеплоить проект? 27 | 28 | – `ansible-playbook -i inventory/production --tags "deploy" app-server.yml -vvv --become-user=app --extra-vars=extra.txt --vault-password-file="~/.ansible/vault.txt"` 29 | 30 | 31 | 32 | Вот с таким и будем бороться. 33 | 34 | Метод борьбы прост и приятен, и напоминает процесс уборки в шкафу. 35 | 36 | Открываем `Makefile`, и складываем туда свою мегакоманду: 37 | 38 | ```make 39 | deploy: 40 | ansible-playbook -i inventory/production --tags "deploy" app-server.yml -vvv --become-user=app --extra-vars=extra.txt --vault-password-file="~/.ansible/vault.txt" 41 | ``` 42 | 43 | 44 | 45 | В следующий раз Вова просто скажет `make deploy`. 46 | 47 | Классно ведь!? Это значит, что Вова: 48 | 49 | - не потратит лишнюю минуту вспоминая синтаксис 50 | - не запутается в ключах команды деплоя 51 | - не будет страдать когда Ansible решит поменять названия половины своих ключей 52 | 53 | 54 | 55 | Дальше действуем по аналогии. 56 | 57 | Почему-то то, что изначально задумывалось простым, например `rails server`, часто обрастает дополнительными изнуряющими подробностями: `bundle exec bin/rails server -p 3001 RAILS_ENV=development`. 58 | 59 | Что с этим делать мы уже знаем: 60 | 61 | ```make 62 | server: 63 | bundle exec bin/rails server -p 3001 RAILS_ENV=development 64 | ``` 65 | 66 | Продолжаем разговор: 67 | 68 | ```make 69 | logs: 70 | tail -f log/development.log 71 | ``` 72 | 73 | В общем идею вы поняли. Дополнительная прелесть в том что нет никакой необходимости это все делать за один раз. Поймал себя на том что опять долго вспоминал длинную команду? Добавляй ее в мэйкфайл! 74 | 75 |
76 | ## 2. Overcoming Make weirdness 77 | 78 | Вова добрался до тестов, радостно добавляет в Makefile строчку для прогона тестов: 79 | 80 | ```make 81 | test: 82 | MINITEST_REPORTER=SpecReporter bundle exec bin/rails test 83 | ``` 84 | 85 | Запускает, и получает привет: 86 | 87 | ``` 88 | $: make test 89 | make: `test' is up to date. 90 | ``` 91 | 92 | – "Эээ, похоже что-то с вашим Make не так" - думает Владимир. 93 | 94 | 95 | 96 | Надо понимать что Make придумывался чтобы билдить всякое, и изначальная семантика команды `make test` заключается в том чтобы сгенерировать папку `test`. 97 | 98 | Соответственно, раз такая папка есть, то запускать ничего уже не надо! (*так думает Make, Вова то как раз с этим не согласен*). 99 | 100 | 101 | 102 | Переубедить Make довольно просто. Надо добавить в Makefile магическую строчку: 103 | 104 | `.PHONY: test` 105 | 106 | Если таких команд несколько, то просто пишем их все через пробел: 107 | 108 | `.PHONY: app test log doc` 109 | 110 | 111 | 112 | Вторая вредность Make заключается в том что он отказывается работать, если, о боже мой, для отступа использованы пробелы, а не символ табуляции: 113 | 114 | ``` 115 | $: make test 116 | Makefile:13: *** missing separator. Stop. 117 | ``` 118 | 119 | Ну такое, да. Если ваш редактор умеет понимать типы файлов, то скорее всего он уже сам догадался использовать табы. Если нет, придется его немного подконфигурить. 120 | 121 | Теперь Вова знает чего опасаться и как этого избегать, так что можно ехать дальше. 122 | 123 |
124 | ## 3. Running multiple commands at once 125 | 126 | Хотим прогнать тесты, и если все ок, то задеплоить? No problemos: 127 | 128 | `make test deploy` 129 | 130 | Да, команды можно составлять в длинные цепочки, и если какая-то из команд фэйлится, то остальные запущены не будут. 131 | 132 | 133 | 134 | ## 4. Subcommands 135 | 136 | В какой-то момент в команде решили что негоже деплоить без запуска тестов и прогон тестов просто захардкодили внутрь команды деплой: 137 | 138 | ```make 139 | deploy: test 140 | ansible-playbook -i inventory/production --tags 'deploy' # ... 141 | ``` 142 | 143 | Т.е. при использовании `make deploy` до деплоя дойдет дело только если пройдут тесты. 144 | 145 |
146 | ## 5. Aliases 147 | 148 | Семен добавил в Makefile команду для прогона миграций, а Вова все никак не может запомнить как она называется. Иногда он пишет `make dbmigrate`, иногда `make db_migrate`, иногда по привычке вообще `make db:migrate`. 149 | 150 | Увы, с последним ничего не поделать. Двоеточия в названиях комманд не поддерживаются. Зато можно смело нафигачить себе алиасов на остальные варианты! Чем Вова и занялся. 151 | 152 | Для этого не нужно копипастить нашу длинную команду несколько раз, достаточно записать вызов оригинала после двоеточия: 153 | 154 | ```make 155 | db-migrate: 156 | bundle exec bin/rails db:migrate 157 | 158 | db_migrate: db-migrate 159 | dbmigrate: db-migrate 160 | ``` 161 | 162 | Придумать годное название для шортката сходу бывает непросто. В таких случая как раз можно насоздавать сразу несколько алиасов, и оставить тот который приживется со временем. 163 | 164 |
165 | ## 6. Multiline commands 166 | 167 | Со временем Вове надоело набирать такую длинную команду, и он заменил ее на `make db` (не забыв добавить `db` в `.PHONY:`) 168 | 169 | И все бы классно, но в какой-то момент разработчики на проекте договорились не коммитить в проект `db/schema.rb` (который авто-обновляется после прогона миграций), а это значит что каждый раз после прогона миграций приходилось выполнять команду `make schema-reset`: 170 | 171 | ```make 172 | schema-reset: 173 | git checkout HEAD -- db/schema.rb 174 | ``` 175 | 176 | К счастью, никто не запрещает запускать несколько команд под одним шорткатом, и команды Make можно вызывать из Makefile: 177 | 178 | ```make 179 | db: 180 | bundle exec bin/rails db:migrate 181 | make schema-reset 182 | 183 | schema-reset: 184 | git checkout HEAD -- db/schema.rb 185 | ``` 186 | 187 | Единственный минус в том, что Make по умолчанию многословен, и печатает каждую команду прежде чем выполнить: 188 | 189 | ``` 190 | $: make db 191 | bundle exec bin/rails db:migrate 192 | # ... 193 | make schema-reset 194 | git checkout HEAD -- db/schema.rb 195 | ``` 196 | 197 | К счастью это легко забороть. 198 | 199 |
200 | ## 7. Suppressing output 201 | 202 | Все что нужно сделать чтобы Make не выводил саму команду, а просто её выполнял, это добавить перед ней символ "@". 203 | 204 | Например, так: 205 | 206 | ```make 207 | hello: 208 | @echo "Привет, Вова!" 209 | ``` 210 | 211 | Соответственно лишний вывод "make schema-reset" прячем так: 212 | 213 | ```make 214 | db: 215 | bundle exec bin/rails db:migrate 216 | @make schema-reset 217 | ``` 218 | 219 | Ура! 220 | 221 |
222 | ## 8. Ignoring errors 223 | 224 | При деплое на staging разрабы тоже решили прогонять тесты: 225 | 226 | ```make 227 | staging-deploy: 228 | @make test 229 | ansible-playbook -i inventory/staging --tags 'deploy' #... 230 | ``` 231 | 232 | Правда быстро выяснилось, что иногда надо задеплоить, даже если тесты падают! 233 | 234 | Чтобы не выпиливать тесты из сценария, но деплоить несмотря на их результат, можно использовать магический префикс "-": 235 | 236 | ```make 237 | staging-deploy: 238 | -@make test 239 | ansible-playbook -i inventory/staging --tags 'deploy' #... 240 | ``` 241 | 242 | 243 | ## 9. Running command only if another one fails 244 | 245 | А можно было поступить по другому. 246 | 247 | ```make 248 | staging-deploy: 249 | @make test || echo "Опять Вова поломал тесты!!" 250 | ansible-playbook -i inventory/staging --tags 'deploy' #... 251 | ``` 252 | 253 | Это даже не фишка Make, это обычный Bash scripting. В результате программа будет каждый раз журить Вову если тесты упали, но и от деплоя отказываться не будет. 254 | 255 |
256 | ## 10. Passing arguments 257 | 258 | Однажды Вове понадобилось стянуть дамп базы со стэйджинга на свой комп. Пришлось напрячь остатки пямяти и разродиться скриптом: 259 | 260 | ```make 261 | staging-fetch-dump: 262 | scp app@staging-server.dev:/path/to/app/db/dump.tgz ./ 263 | ``` 264 | 265 | Только вот неплохо бы его сделать чуть более полезным. Вдруг понадобится какой-то еще файл стягивать. 266 | 267 | По такому случаю можно передать название файла в качестве аргумента: 268 | 269 | ```make 270 | staging-fetch: 271 | scp app@staging-server.dev:/path/to/app/$(F)/ ./ 272 | ``` 273 | 274 | Вызов команды теперь будет выглядеть так: 275 | 276 | `make staging-fetch F=db/dump.tgz` 277 | 278 |
279 | ## 11. Seamless arguments 280 | 281 | Однако в случае когда аргумент всего один, было бы классно избавиться от необходимости запоминать название этого самого аргумента и вызывать команду прямо так: `make staging-fetch db/dump.tgz` 282 | 283 | Этого можно добиться, но только с помочью черной магии. Надо добавить в Makefile вот такую конструкцию: 284 | 285 | ```make 286 | ARGS = $(filter-out $@,$(MAKECMDGOALS)) 287 | %: 288 | @: 289 | ``` 290 | 291 | Шорткат при таких раскладах выглядит вот так: 292 | 293 | ``` 294 | staging-fetch: 295 | scp app@staging-server.dev:/path/to/app/$(ARGS)/ ./ 296 | ``` 297 | 298 | Но магия на то и черная, что у неё есть неприятный спецэффект – уже после того как все успешно выполнится, прилетает вот такое сообщение: 299 | 300 | ``` 301 | make: *** No rule to make target 'db/dump.tgz'. Stop. 302 | ``` 303 | 304 | Можете почитать [подробности того как это работает](https://stackoverflow.com/a/6273809/1334666), чуть ниже вроде даже показывают как победить проблему с ошибкой, но мне это победить не удалось. 305 | 306 | Короче говоря, Вова смирился, и решил что можно заплатить такую цену за такую фичу, ну а вам решать самим. 307 | 308 |
309 | ## 12. Advanced scripting 310 | 311 | Внезапно админы запилили все так, что теперь на каждый фичебранч поднимается по отдельному стэйджингу. 312 | 313 | И все бы классно, но теперь в наши крутые шорткаты для работы со стэйджингом придется добавлять по еще одной переменной - имени сервера: 314 | 315 | ```make 316 | ssh: 317 | ssh app@$(S) 318 | 319 | staging-fetch: 320 | scp app@$(S):/path/to/app/$(F)/ ./ 321 | ``` 322 | 323 | ... [TO BE CONTINUED IN PRO VERSION](https://gum.co/makefile-ru): ... 324 | 325 | 1. [Advanced scripting](https://gum.co/makefile-ru) 326 | 2. [Putting things in order](https://gum.co/makefile-ru) 327 | 3. [Naming conventions](https://gum.co/makefile-ru) 328 | 4. [Full workflow automation](https://gum.co/makefile-ru) 329 | 5. [Guiding principles](https://gum.co/makefile-ru) 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | [![](https://i.imgur.com/MhU79hR.png)](https://makefile.site) 342 | 343 | -------------------------------------------------------------------------------- /modern-make-handbook.md: -------------------------------------------------------------------------------- 1 | # Modern Make Handbook (v. 0.6) 2 | 3 | [![](https://i.imgur.com/dYVUnUu.png)](https://makefile.site) 4 | 5 | 6 | 7 | 8 | [TOC] 9 | 10 | 11 |
12 | ## 1. Making your library of shortcuts 13 | 14 | – What cats say when they’re hungry? 15 | 16 | – Meow! 17 | 18 | 19 | 20 | – What dogs say when they smell danger? 21 | 22 | – Woof-woof! 23 | 24 | 25 | 26 | – And what does Bob say when he’s deploying project? 27 | 28 | – `ansible-playbook -i inventory/production --tags “deploy” app-server.yml -vvv --become-user=app --extra-vars=extra.txt --vault-password-file="~/.ansible/vault.txt"` 29 | 30 | 31 | 32 | This is what we’re going to fix. 33 | 34 | It is not gonna be hard. It will be an easy and pleasant process. Just like organizing a closet. 35 | 36 | Open `Makefile` and put your mega-command in there: 37 | 38 | ```make 39 | deploy: 40 | ansible-playbook -i inventory/production --tags “deploy” app-server.yml -vvv --become-user=app --extra-vars=extra.txt --vault-password-file="~/.ansible/vault.txt" 41 | ``` 42 | 43 | 44 | Next time Bob will have to say just `make deploy`. 45 | 46 | Cool, huh? It means that: 47 | 48 | - Bob saves time because he doesn't have to remember all the details of the deploy command 49 | - Bob will never make a mistake in the deploy command 50 | - Bob is not going to freak out when Ansible renames half of their flags 51 | 52 | 53 | Let’s move on. 54 | 55 | 56 | Often, things that supposed to be simple, like `rails server`, overgrow with additional debilitating details: `bundle exec bin/rails server -p 3001 RAILS_ENV=development`.  57 | 58 | Luckily we already know what to do: 59 | 60 | ```make 61 | server: 62 | bundle exec bin/rails server -p 3001 RAILS_ENV=development 63 | ``` 64 | 65 | and: 66 | 67 | ```make 68 | logs: 69 | tail -f log/development.log 70 | ``` 71 | 72 | Savor it: `make deploy`, `make server`, `make logs` 73 | 74 | Of course, Bob commits the Makefile to the repository, so that his colleagues can use the shortcuts too! 75 | 76 | 77 | 78 |
79 | ## 2. Overcoming Make weirdness 80 | 81 | Inspired, Bob keeps cleaning up: 82 | 83 | ```make 84 | test: 85 | MINITEST_REPORTER=SpecReporter bundle exec bin/rails test 86 | ``` 87 | 88 | Then some weirdness happens: 89 | 90 | ``` 91 | $: make test 92 | make: `test’ is up to date. 93 | ``` 94 | 95 | — "Looks like something is very wrong with your Make!” - he thinks. 96 | 97 | The original purpose of Make is to automate complex builds for C/C++ projects. So, the semantics of `make test` assumes that `test` directory should be generated as a result. 98 | 99 | If such a directory exists, Make assumes there's no need to execute anything. This is exactly what happened since every Rails project has a `test` directory. 100 | 101 | To persuade Make, Bob has to add one magical rule to `Makefile`: 102 | 103 | `.PHONY: test` 104 | 105 | If there are multiple commands like this, we can add them all: 106 | 107 | `.PHONY: app test log doc` 108 | 109 | 110 | Another surprise is that Make is very picky about indentation. It refuses to work if you use spaces: 111 | 112 | ``` 113 | $: make test 114 | Makefile:13: *** missing separator. Stop. 115 | ``` 116 | 117 | If your editor detects the file format correctly, you don't have to do anything. If not, then just configure it accordingly. 118 | 119 | 120 | Now Bob is warned, he knows how to avoid common problems, so we can move on. 121 | 122 |
123 | ## 3. Running multiple commands at once 124 | 125 | What if we want to run the tests, and if they pass, then deploy our code? No problemo: 126 | 127 | `make test deploy` 128 | 129 | Yup, you can combine commands in long chains. If one fails, the rest of them going to be skipped. 130 | 131 | 132 | ## 4. Subcommands 133 | 134 | At some point, Bob's team decides that tests execution should be a part of the deployment process, so they just hardcoded `test` command into deploy instructions: 135 | 136 | ```make 137 | deploy: test 138 | ansible-playbook -i inventory/production --tags ‘deploy’ # ... 139 | ``` 140 | This means that each time you run `make deploy`, `make test` is called first. And only if it succeeds, `deploy` will be executed. 141 | 142 |
143 | ## 5. Aliases 144 | 145 | Alice adds a new command to run migrations, but Bob keeps forgetting how it is called. He runs `make dbmigrate`, `make db_migrate`, and even `make db:migrate`, but keeps getting the error: 146 | 147 | ``` 148 | make: *** No rule to make target '*'. Stop. 149 | ``` 150 | 151 | We can fix this problem with aliases! Unfortunately, the latter will not work, because `make` command names can't contain colons. But for the rest of the typos we can do it easily, even without copying and pasting: 152 | 153 | ```make 154 | db-migrate: 155 | bundle exec bin/rails db:migrate 156 | 157 | db_migrate: db-migrate 158 | dbmigrate: db-migrate 159 | ``` 160 | 161 | Sometimes it is hard to come up with a handy name for a shortcut. In this case, just create a bunch of aliases and keep the most used one after a while. 162 | 163 |
164 | ## 6. Multiline commands 165 | 166 | After a while, the team decided to replace `make db-migrate` with just `make db`, which is impossible to forget. 167 | Of course, they added `db` to `.PHONY:`, because Rails projects have `db` directory as well. 168 | 169 | So far so good, but on the next day, the team decides that they not going to commit `db/schema.rb` anymore, but delegate it to the CI system. The problem is that Rails generates the new version of `schema.rb` every time you run migrations. 170 | 171 | Not a big problem actually: 172 | 173 | ```make 174 | schema-reset: 175 | git checkout HEAD -- db/schema.rb 176 | ``` 177 | 178 | 179 | Luckily, we can run multiple commands under one shortcut, and you can nest make shortcuts: 180 | 181 | ```make 182 | db: 183 | bundle exec bin/rails db:migrate 184 | make schema-reset 185 | 186 | schema-reset: 187 | git checkout HEAD -- db/schema.rb 188 | ``` 189 | 190 | Make prints each command before executing it, so the output is a bit verbose: 191 | 192 | ``` 193 | $: make db 194 | bundle exec bin/rails db:migrate  195 | # ... 196 | make schema-reset 197 | git checkout HEAD -- db/schema.rb 198 | ``` 199 | 200 | The good news is that it is very easy to fix! 201 | 202 | 203 | 204 |
205 | ## 7. Making Make less verbose 206 | 207 | When you don't want a command to be printed, and just want Make to execute it, prepend it with `@`: 208 | 209 | ```make 210 | hello: 211 | @echo “Hi, Bob!” 212 | ``` 213 | 214 | So, in our case: 215 | 216 | ```make 217 | db: 218 | bundle exec bin/rails db:migrate 219 | @make schema-reset 220 | ``` 221 | 222 | Yay! 223 | 224 | 225 |
226 | ## 8. Ignoring errors 227 | 228 | Bob’s team decides to run tests before deploying to staging as well: 229 | 230 | ```make 231 | staging-deploy:  232 | @make test 233 | ansible-playbook -i inventory/staging --tags ‘deploy’ #... 234 | ``` 235 | 236 | However, sometimes you have to deploy to staging even if tests are failing. 237 | 238 | To keep tests running, but still deploy even if they do not pass, we add another magical prefix: `-`. 239 | 240 | ```make 241 | staging-deploy:  242 | -@make test 243 | ansible-playbook -i inventory/staging --tags ‘deploy’ #... 244 | ``` 245 | 246 | 247 | ## 9. Running command only if another one fails 248 | 249 | There is one more way to achieve the same effect: 250 | 251 | ```make 252 | staging-deploy:  253 | @make test || echo “Looks like Bob broke tests again!!” 254 | ansible-playbook -i inventory/staging --tags ‘deploy’ #... 255 | ``` 256 | 257 | It's even not a feature of Make - it's a regular shell scripting. It will condemn Bob for broken tests every time they fail but will deploy the project anyway. 258 | 259 | If we don’t want lower Bob's self-esteem, we can do it like this: 260 | 261 | ```make 262 | staging-deploy:  263 | @make test || true 264 | ansible-playbook -i inventory/staging --tags ‘deploy’ #... 265 | ``` 266 | 267 |
268 | ## 10. Passing arguments 269 | 270 | Bob had to download a database dump from the staging server to his local machine. He decides to add it as a shortcut: 271 | 272 | ```make 273 | staging-fetch-dump: 274 | scp app@staging-server.dev:/path/to/app/db/dump.tgz ./ 275 | ``` 276 | 277 | A good start, but how about to make it more useful, so we could use it to download any file? 278 | 279 | We can pass a the filename as an argument: 280 | 281 | ```make 282 | staging-fetch: 283 | scp app@staging-server.dev:/path/to/app/$(F)/ ./ 284 | ``` 285 | 286 | And we call it like this: 287 | 288 | `make staging-fetch F=db/dump.tgz` 289 | 290 | 291 |
292 | ## 11. Seamless arguments 293 | 294 | What if we could simplify the command by skipping the name of the argument since we have only one here? 295 | 296 | Could we just do `make staging-fetch db/dump.tgz`? 297 | 298 | The answer is yes! We can do it with a bit of black magic. We have to add the following statement into the `Makefile`: 299 | 300 | ```make 301 | ARGS = $(filter-out $@,$(MAKECMDGOALS)) 302 | %: 303 | @: 304 | ``` 305 | 306 | Your shortcut will turn into something that looks like this: 307 | 308 | ``` 309 | staging-fetch: 310 | scp app@staging-server.dev:/path/to/app/$(ARGS)/ ./ 311 | ``` 312 | 313 | We called it "black magic" for a reason. This trick has one annoying side effect. After the script is executed, you get an error message like this: 314 | 315 | ``` 316 | make: *** No rule to make target ‘db/dump.tgz’. Stop. 317 | ``` 318 | 319 | Here is a [post on StackOverflow](https://stackoverflow.com/a/6273809/1334666) that explains how it works and even contains a fix for this problem. Although, Bob couldn‘t make it work but he decided that this is the price he is ready to pay. 320 | 321 | 322 |
323 | ## 12. Advanced scripting 324 | 325 | Another day the DevOps team announces that from now on each feature branch will be deployed to a separate staging server. 326 | 327 | Sounds great, but now for all our staging-related shortcuts we have to specify additional variable – URL of the server: 328 | 329 | ```make 330 | ssh: 331 |   ssh app@$(S) 332 | 333 | staging-fetch: 334 |   scp app@$(S):/path/to/app/$(F)/ ./ 335 | ``` 336 | 337 | 338 | 339 | ... [TO BE CONTINUED IN PRO VERSION](https://gum.co/makefile-ru): ... 340 | 341 | 1. [Advanced scripting](https://gum.co/makefile-ru) 342 | 2. [Putting things in order](https://gum.co/makefile-ru) 343 | 3. [Naming conventions](https://gum.co/makefile-ru) 344 | 4. [Full workflow automation](https://gum.co/makefile-ru) 345 | 5. [Guiding principles](https://gum.co/makefile-ru) 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | [![](https://i.imgur.com/X1sXATm.png)](https://makefile.site) 358 | 359 | --------------------------------------------------------------------------------