Skip to content

Commit 10e4e4b

Browse files
committed
Add test coverage and make build release manual
1 parent 6e9b56a commit 10e4e4b

14 files changed

Lines changed: 1180 additions & 104 deletions

File tree

.github/workflows/ci.yml

Lines changed: 226 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,240 @@ name: CI
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [main, develop, release/**]
66
pull_request:
7-
branches: [ main ]
7+
branches: [main, develop]
8+
9+
permissions:
10+
actions: write
11+
contents: read
12+
id-token: write
13+
packages: write
814

915
jobs:
1016
test:
1117
runs-on: ubuntu-latest
18+
1219
strategy:
20+
fail-fast: false
1321
matrix:
14-
ruby-version: ['2.7', '3.0', '3.1', '3.2', '3.3']
15-
22+
ruby-version: ["2.7", "3.0", "3.1", "3.2", "3.3"]
23+
1624
steps:
17-
- uses: actions/checkout@v4
18-
19-
- name: Set up Ruby ${{ matrix.ruby-version }}
20-
uses: ruby/setup-ruby@v1
21-
with:
22-
ruby-version: ${{ matrix.ruby-version }}
23-
bundler-cache: true
24-
25-
- name: Run tests
26-
run: bundle exec rake spec
27-
28-
- name: Test CLI
29-
run: bundle exec bin/gemplate --help
30-
31-
publish:
25+
- uses: actions/checkout@v4
26+
27+
- name: Set up Ruby ${{ matrix.ruby-version }}
28+
uses: ruby/setup-ruby@v1
29+
with:
30+
ruby-version: ${{ matrix.ruby-version }}
31+
bundler-cache: true
32+
33+
- name: Run tests with coverage
34+
run: bundle exec rspec
35+
36+
- name: Test CLI
37+
run: bundle exec bin/gemplate --help
38+
39+
- name: Upload coverage artifact (Ruby 3.3 only)
40+
if: matrix.ruby-version == '3.3'
41+
uses: actions/upload-artifact@v4
42+
with:
43+
name: coverage-report
44+
path: coverage/
45+
retention-days: 1
46+
47+
- name: Run RuboCop (Ruby 3.3 only)
48+
if: matrix.ruby-version == '3.3'
49+
run: bundle exec rubocop || true
50+
continue-on-error: true
51+
52+
coverage:
53+
runs-on: ubuntu-latest
3254
needs: test
55+
56+
steps:
57+
- uses: actions/checkout@v4
58+
59+
- name: Download coverage artifact
60+
uses: actions/download-artifact@v4
61+
with:
62+
name: coverage-report
63+
path: coverage/
64+
65+
- name: Upload coverage to Qlty
66+
uses: qltysh/qlty-action/coverage@v1
67+
continue-on-error: true
68+
env:
69+
QLTY_COVERAGE_TOKEN: ${{ secrets.QLTY_COVERAGE_TOKEN }}
70+
with:
71+
oidc: true
72+
files: coverage/coverage.json
73+
74+
- name: Run Qlty code quality checks
75+
run: |
76+
curl -sSfL https://qlty.sh | sh
77+
echo "$HOME/.qlty/bin" >> $GITHUB_PATH
78+
~/.qlty/bin/qlty check || true
79+
continue-on-error: true
80+
81+
security:
82+
runs-on: ubuntu-latest
83+
84+
steps:
85+
- uses: actions/checkout@v4
86+
87+
- name: Set up Ruby
88+
uses: ruby/setup-ruby@v1
89+
with:
90+
ruby-version: "3.3"
91+
bundler-cache: true
92+
93+
- name: Run bundle audit
94+
run: |
95+
gem install bundler-audit
96+
bundle audit --update || true
97+
continue-on-error: true
98+
99+
build:
100+
runs-on: ubuntu-latest
101+
needs: [test, coverage, security]
102+
if: github.event_name == 'push'
103+
104+
steps:
105+
- uses: actions/checkout@v4
106+
107+
- name: Set up Ruby
108+
uses: ruby/setup-ruby@v1
109+
with:
110+
ruby-version: "3.3"
111+
bundler-cache: true
112+
113+
- name: Modify version for develop branch
114+
if: github.ref == 'refs/heads/develop'
115+
run: |
116+
SHORT_SHA=$(git rev-parse --short HEAD)
117+
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.dev.${SHORT_SHA}'/" lib/gemplate/version.rb
118+
echo "VERSION_SUFFIX=.dev.${SHORT_SHA}" >> $GITHUB_ENV
119+
120+
- name: Modify version for release branch
121+
if: startsWith(github.ref, 'refs/heads/release/')
122+
run: |
123+
SHORT_SHA=$(git rev-parse --short HEAD)
124+
sed -i "s/VERSION = '\([^']*\)'/VERSION = '\1.rc.${SHORT_SHA}'/" lib/gemplate/version.rb
125+
echo "VERSION_SUFFIX=.rc.${SHORT_SHA}" >> $GITHUB_ENV
126+
127+
- name: Set version suffix for main
128+
if: github.ref == 'refs/heads/main'
129+
run: echo "VERSION_SUFFIX=" >> $GITHUB_ENV
130+
131+
- name: Build gem
132+
run: gem build gemplate.gemspec
133+
134+
- name: Get gem info
135+
id: gem_info
136+
run: |
137+
GEM_FILE=$(ls *.gem)
138+
GEM_VERSION=$(echo $GEM_FILE | sed 's/gemplate-\(.*\)\.gem/\1/')
139+
echo "gem_file=$GEM_FILE" >> $GITHUB_OUTPUT
140+
echo "gem_version=$GEM_VERSION" >> $GITHUB_OUTPUT
141+
142+
- name: Store gem artifact
143+
uses: actions/upload-artifact@v4
144+
with:
145+
name: gem-${{ steps.gem_info.outputs.gem_version }}
146+
path: "*.gem"
147+
retention-days: 30
148+
149+
deploy:
33150
runs-on: ubuntu-latest
34-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
35-
151+
needs: build
152+
if: github.ref == 'refs/heads/main'
153+
environment:
154+
name: production
155+
url: https://github.com/TwilightCoders/gemplate/packages
156+
permissions:
157+
contents: read
158+
packages: write
159+
36160
steps:
37-
- uses: actions/checkout@v4
38-
39-
- name: Set up Ruby
40-
uses: ruby/setup-ruby@v1
41-
with:
42-
ruby-version: '3.3'
43-
bundler-cache: true
44-
45-
- name: Build gem
46-
run: gem build gemplate.gemspec
47-
48-
- name: Publish to GitHub Packages
49-
run: |
50-
mkdir -p $HOME/.gem
51-
touch $HOME/.gem/credentials
52-
chmod 0600 $HOME/.gem/credentials
53-
printf -- "---\n:github: Bearer ${GITHUB_TOKEN}\n" > $HOME/.gem/credentials
54-
gem push --KEY github --host https://rubygems.pkg.github.com/TwilightCoders *.gem
55-
env:
56-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
161+
- uses: actions/checkout@v4
162+
163+
- name: Set up Ruby
164+
uses: ruby/setup-ruby@v1
165+
with:
166+
ruby-version: "3.3"
167+
bundler-cache: true
168+
169+
- name: Download gem artifact
170+
uses: actions/download-artifact@v4
171+
with:
172+
pattern: gem-*
173+
merge-multiple: true
174+
175+
- name: Show deployment details
176+
run: |
177+
echo "## 🚀 Ready to Deploy" >> $GITHUB_STEP_SUMMARY
178+
echo "**Gem**: $(ls *.gem)" >> $GITHUB_STEP_SUMMARY
179+
echo "**Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
180+
echo "**Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
181+
echo "**Size**: $(ls -lh *.gem | awk '{print $5}')" >> $GITHUB_STEP_SUMMARY
182+
echo "" >> $GITHUB_STEP_SUMMARY
183+
echo "### Manual Approval Required" >> $GITHUB_STEP_SUMMARY
184+
echo "This deployment uses the \`production\` environment and can require manual approval." >> $GITHUB_STEP_SUMMARY
185+
echo "" >> $GITHUB_STEP_SUMMARY
186+
echo "**To enable manual approval:**" >> $GITHUB_STEP_SUMMARY
187+
echo "1. Go to **Settings** → **Environments** → **production**" >> $GITHUB_STEP_SUMMARY
188+
echo "2. Enable **Required reviewers** and add yourself" >> $GITHUB_STEP_SUMMARY
189+
echo "3. Optionally enable **Wait timer** for additional safety" >> $GITHUB_STEP_SUMMARY
190+
echo "" >> $GITHUB_STEP_SUMMARY
191+
echo "📖 **See:** [GitHub Docs - Reviewing Deployments](https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/reviewing-deployments)" >> $GITHUB_STEP_SUMMARY
192+
echo "" >> $GITHUB_STEP_SUMMARY
193+
echo "Once configured, you'll get a **Review deployments** button to approve/reject releases." >> $GITHUB_STEP_SUMMARY
194+
195+
- name: Publish to GitHub Packages
196+
id: publish
197+
continue-on-error: true
198+
run: |
199+
mkdir -p ~/.gem
200+
cat << EOF > ~/.gem/credentials
201+
---
202+
:github: Bearer ${{ secrets.GITHUB_TOKEN }}
203+
EOF
204+
chmod 600 ~/.gem/credentials
205+
206+
# Try to publish, capturing output
207+
if gem push --key github --host https://rubygems.pkg.github.com/TwilightCoders *.gem 2>&1 | tee publish_output.log; then
208+
echo "success=true" >> $GITHUB_OUTPUT
209+
echo "message=Successfully published $(ls *.gem)" >> $GITHUB_OUTPUT
210+
else
211+
# Check if it's a version conflict (common scenario)
212+
if grep -q "already exists" publish_output.log || grep -q "Repushing of gem versions is not allowed" publish_output.log; then
213+
echo "success=false" >> $GITHUB_OUTPUT
214+
echo "message=Version $(ls *.gem) already exists in GitHub Packages - no action needed" >> $GITHUB_OUTPUT
215+
else
216+
echo "success=false" >> $GITHUB_OUTPUT
217+
echo "message=Failed to publish: $(cat publish_output.log)" >> $GITHUB_OUTPUT
218+
fi
219+
fi
220+
221+
- name: Deployment summary
222+
run: |
223+
if [ "${{ steps.publish.outputs.success }}" == "true" ]; then
224+
echo "## ✅ Deployment Complete" >> $GITHUB_STEP_SUMMARY
225+
echo "${{ steps.publish.outputs.message }}" >> $GITHUB_STEP_SUMMARY
226+
else
227+
echo "## ⚠️ Deployment Skipped" >> $GITHUB_STEP_SUMMARY
228+
echo "${{ steps.publish.outputs.message }}" >> $GITHUB_STEP_SUMMARY
229+
echo "" >> $GITHUB_STEP_SUMMARY
230+
echo "This is typically expected when the version already exists." >> $GITHUB_STEP_SUMMARY
231+
fi
232+
233+
- name: Create build summary
234+
run: |
235+
echo "## Gem Built Successfully 💎" >> $GITHUB_STEP_SUMMARY
236+
echo "- **Version**: ${{ steps.gem_info.outputs.gem_version }}" >> $GITHUB_STEP_SUMMARY
237+
echo "- **File**: ${{ steps.gem_info.outputs.gem_file }}" >> $GITHUB_STEP_SUMMARY
238+
echo "- **Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
239+
echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
240+
echo "" >> $GITHUB_STEP_SUMMARY
241+
echo "🚀 **Ready to publish!** Use the 'Manual Release' workflow to publish this gem." >> $GITHUB_STEP_SUMMARY

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,4 @@ Thumbs.db
8181
#####################
8282
.claude/
8383
CLAUDE.md
84+
.vscode/

.qlty/qlty.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,6 @@ name = "trufflehog"
8989

9090
[[plugin]]
9191
name = "yamllint"
92+
93+
[coverage]
94+
lcov_path = "coverage/lcov/gemplate.lcov"

.rubocop.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
AllCops:
2+
TargetRubyVersion: 2.7
3+
NewCops: enable
4+
Exclude:
5+
- "vendor/**/*"
6+
- "tmp/**/*"
7+
- "coverage/**/*"
8+
9+
# Disable some common rules for gem development
10+
Layout/LineLength:
11+
Max: 120
12+
13+
Style/Documentation:
14+
Enabled: false
15+
16+
Metrics/MethodLength:
17+
Max: 20
18+
Exclude:
19+
- lib/gemplate/generator.rb # Generator methods legitimately need to be longer
20+
- spec/**/* # Test methods can be longer for readability
21+
22+
Metrics/ClassLength:
23+
Max: 250
24+
Exclude:
25+
- lib/gemplate/generator.rb # Generator class is complex by nature
26+
27+
Metrics/AbcSize:
28+
Max: 25
29+
Exclude:
30+
- lib/gemplate/generator.rb
31+
32+
Metrics/CyclomaticComplexity:
33+
Max: 12
34+
Exclude:
35+
- lib/gemplate/generator.rb
36+
37+
Metrics/PerceivedComplexity:
38+
Max: 12
39+
Exclude:
40+
- lib/gemplate/generator.rb
41+
42+
Metrics/BlockLength:
43+
Exclude:
44+
- spec/**/*
45+
- '*.gemspec'
46+
47+
Style/StringLiterals:
48+
EnforcedStyle: single_quotes
49+
50+
Layout/TrailingEmptyLines:
51+
EnforcedStyle: final_newline

bin/console

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env ruby
2+
3+
require "bundler/setup"
4+
require "gemplate"
5+
6+
# You can add fixtures and/or initialization code here to make experimenting
7+
# with your gem easier. You can also use a different console, if you like.
8+
9+
# (If you use this, don't forget to add pry to your Gemfile!)
10+
# require "pry"
11+
# Pry.start
12+
13+
require "irb"
14+
IRB.start(__FILE__)

gemplate.gemspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,8 @@ Gem::Specification.new do |spec|
2626
spec.add_development_dependency 'rake', '~> 12.0'
2727
spec.add_development_dependency 'rspec', '~> 3.0'
2828
spec.add_development_dependency 'pry-byebug', '~> 3'
29+
spec.add_development_dependency 'simplecov', '~> 0.22'
30+
spec.add_development_dependency 'simplecov_json_formatter', '~> 0.1'
31+
spec.add_development_dependency 'rubocop', '~> 1.50'
2932

3033
end

lib/gemplate/cli.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def run
1515
when 'new'
1616
create_gem(@args[1])
1717
when 'version', '-v', '--version'
18-
puts Gemplate::VERSION
18+
return puts Gemplate::VERSION
1919
when 'help', '-h', '--help', nil
2020
show_help
2121
else
@@ -90,4 +90,4 @@ def show_help
9090
HELP
9191
end
9292
end
93-
end
93+
end

0 commit comments

Comments
 (0)