Skip to content
This repository was archived by the owner on Dec 18, 2020. It is now read-only.

Commit 3e88908

Browse files
authored
Merge pull request #99 from fastruby/post/calculate-tech-debt-with-skunk-and-gh-actions
Initial commit with article about skunk and github actions
2 parents b1e3c7b + aa0f2c4 commit 3e88908

File tree

1 file changed

+221
-0
lines changed

1 file changed

+221
-0
lines changed
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
---
2+
layout: post
3+
title: "How to Calculate Tech Debt Using Skunk on GitHub Actions"
4+
date: 2020-02-12 9:16:00
5+
categories: ["code-quality"]
6+
author: etagwerker
7+
---
8+
9+
In preparation for my talk at [RubyConf Australia](https://www.rubyconf.org.au/) this
10+
month, I've been working on a way to make it easy for anyone to run [`skunk`](https://www.fastruby.io/blog/code-quality/intruducing-skunk-stink-score-calculator.html) on
11+
their Ruby projects. In order to do that I decided to use GitHub Actions. It's a powerful
12+
service by GitHub and it's quite easy to set up.
13+
14+
This is an article about the process that I followed and how you can use it in your own
15+
application.
16+
17+
<!--more-->
18+
19+
[GitHub Actions have been around for more than a year](https://github.blog/2018-10-17-action-demos/)
20+
and I had been meaning to play around with them to incorporate some automation to
21+
our workflows at [FastRuby.io](https://fastruby.io). The good news is that [GoRails](https://gorails.com)
22+
already published an article about setting up CI in your Rails app:
23+
[Continuous Integration with GitHub Actions](https://gorails.com/episodes/github-actions-continuous-integration-ruby-on-rails)
24+
25+
After following those steps, I ended up with a copy/pasted YAML file that looked like this:
26+
27+
```yaml
28+
# .github/workflows/ci.yml
29+
30+
name: CI
31+
on: [push]
32+
jobs:
33+
  test:
34+
    runs-on: ubuntu-latest
35+
    services:
36+
      db:
37+
        image: postgres:11
38+
        ports: ['5432:5432']
39+
        options: >-
40+
          --health-cmd pg_isready
41+
          --health-interval 10s
42+
          --health-timeout 5s
43+
          --health-retries 5
44+
      redis:
45+
        image: redis
46+
        ports: ['6379:6379']
47+
        options: --entrypoint redis-server
48+
49+
    steps:
50+
      - uses: actions/checkout@v1
51+
      - name: Setup Ruby
52+
        uses: actions/setup-ruby@v1
53+
        with:
54+
          ruby-version: 2.6.x
55+
      - uses: borales/[email protected]
56+
        with:
57+
          cmd: install
58+
      - name: Build and run tests
59+
        env:
60+
          DATABASE_URL: postgres://postgres:@localhost:5432/test
61+
          REDIS_URL: redis://localhost:6379/0
62+
          RAILS_ENV: test
63+
          RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
64+
        run: |
65+
          sudo apt-get -yqq install libpq-dev
66+
          gem install bundler
67+
          bundle install --jobs 4 --retry 3
68+
          bundle exec rails db:prepare
69+
          bundle exec rails test
70+
```
71+
72+
Considering that [`skunk`](https://github.com/fastruby/skunk) is a Ruby gem (it
73+
doesn't need Rails, Redis, nor Postgres) and I didn't need all the steps I copied
74+
from the GoRails tutorial, I thought it was best to simplify it to look like this:
75+
76+
```yaml
77+
# .github/workflows/skunk.yml
78+
79+
name: Skunk
80+
on: [push]
81+
82+
jobs:
83+
  skunk:
84+
    runs-on: ubuntu-latest
85+
86+
    steps:
87+
      - uses: actions/checkout@v1
88+
      - name: Setup Ruby
89+
        uses: actions/setup-ruby@v1
90+
        with:
91+
          ruby-version: 2.6.x
92+
      - name: Run Skunk on Project
93+
        run: |
94+
          gem install skunk
95+
          skunk lib/
96+
```
97+
98+
This tells [GitHub](https://github.com) to run the [`skunk`](https://github.com/fastruby/skunk)
99+
action every time there is any push to GitHub. To see an entire list
100+
of events that you can configure: [Webhook Events](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows#webhook-events)
101+
102+
There are only two steps:
103+
104+
1. Setup my Ruby environment. I'm going to need this because `skunk` is a Ruby gem.
105+
1. Install the `skunk` gem and run it on the `lib/` directory.
106+
107+
I really like that the configuration file is easy to read and understand. The
108+
order of the steps defined in the `steps` section is **important**. It will run
109+
steps synchronously, from top to bottom. If you want to run `skunk` for a Rails
110+
application, you can change the last step to `skunk app/`
111+
112+
The next thing I wanted to do is run `skunk` on a pull request in order to
113+
compare the [_Stink Score_](https://github.com/fastruby/skunk#what-is-the-stinkscore)
114+
between the pull request and `master`. This will help us answer this question:
115+
116+
> Are we increasing or decreasing the tech debt average in our project?
117+
118+
In order to do this, I had to tweak the call to `skunk` to use the `--branch`
119+
option:
120+
121+
```yaml
122+
# .github/workflows/skunk.yml
123+
124+
name: Skunk
125+
on: [push]
126+
127+
jobs:
128+
skunk:
129+
runs-on: ubuntu-latest
130+
131+
steps:
132+
- uses: actions/checkout@v1
133+
- name: Setup Ruby
134+
uses: actions/setup-ruby@v1
135+
with:
136+
ruby-version: 2.6.x
137+
- name: Run Skunk on Project
138+
run: |
139+
gem install skunk
140+
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
141+
if [[ "$CURRENT_BRANCH" != "master" ]]; then
142+
echo "Executing within branch: $CURRENT_BRANCH"
143+
skunk lib/ -b master
144+
else
145+
echo "Executing within master branch"
146+
skunk lib/
147+
fi
148+
```
149+
150+
There is some `bash` logic in there: The GitHub Action will [compare your branch vs. master](https://github.com/fastruby/skunk#comparing-one-branch-vs-another) if
151+
it is running within the context of a pull request, or [generate a tech debt report](https://github.com/fastruby/skunk#getting-a-sorted-list-of-stinkiest-files) if
152+
it is running a commit pushed to the `master` branch.
153+
154+
One last thing I had to add was a step to generate [SimpleCov](https://github.com/colszowka/simplecov)'s
155+
resultset JSON file. Skunk is most useful when it considers code coverage data.
156+
[The StinkScore is a combination of code smells; complexity; and code coverage data](https://github.com/fastruby/skunk#what-is-the-stinkscore).
157+
158+
I tweaked the steps configuration to look like this:
159+
160+
```yaml
161+
steps:
162+
- uses: actions/checkout@v1
163+
- name: Setup Ruby
164+
uses: actions/setup-ruby@v1
165+
with:
166+
ruby-version: 2.6.x
167+
- name: Run test suite with COVERAGE=true
168+
run: |
169+
gem install bundler
170+
bundle install --jobs 4 --retry 3
171+
COVERAGE=true bundle exec rake test
172+
- name: Run Skunk on Project
173+
run: |
174+
gem install skunk
175+
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
176+
if [[ "$CURRENT_BRANCH" != "master" ]]; then
177+
echo "Executing within branch: $CURRENT_BRANCH"
178+
skunk lib/ -b master
179+
else
180+
echo "Executing within master branch"
181+
skunk lib/
182+
fi
183+
```
184+
185+
Now you can see the difference in tech debt between `master` and your pull
186+
request:
187+
188+
```
189+
Base branch (master) average stink score: 13.42
190+
Feature branch ((HEAD detached at 0315f34)) average stink score: 13.42
191+
Score: 13.42
192+
```
193+
194+
This particular example shows that there is no difference in my application's
195+
technical debt: [https://github.com/fastruby/skunk/pull/26](https://github.com/fastruby/skunk/pull/26).
196+
That's because I didn't change any Ruby code (just a YAML file).
197+
198+
You can see the GitHub Action run over here:
199+
[https://github.com/fastruby/skunk/runs/437118684](https://github.com/fastruby/skunk/runs/437118684)
200+
201+
## Final Thoughts
202+
203+
GitHub Actions can be very useful when you want to run something really quickly
204+
without setting up your own development environment. It can take a lot of trial
205+
and error to get the final configuration right.
206+
207+
If you wanted to give `skunk` a try, now there are _no more excuses_. You don't
208+
need to install anything in your environment. You can add this GitHub workflow
209+
and that's it:
210+
211+
<script src="https://gist.github.com/etagwerker/52e0add0af4281ed38fdc54a502b653f.js"></script>
212+
213+
I hope you can use this free and open source tool to find out your tech debt
214+
hot spots!
215+
216+
## References
217+
218+
- You can see all the trial and error that went into writing this article:
219+
[https://github.com/fastruby/skunk/actions?query=workflow%3ASkunk](https://github.com/fastruby/skunk/actions?query=workflow%3ASkunk)
220+
- A new update to GitHub Actions adds even more features to it:
221+
[https://github.blog/2020-02-06-manage-secrets-and-more-with-the-github-actions-api/](https://github.blog/2020-02-06-manage-secrets-and-more-with-the-github-actions-api/)

0 commit comments

Comments
 (0)