Skip to content

Commit d41f779

Browse files
authored
Add CI and PR workflows (#91)
1 parent e348aa7 commit d41f779

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed

.github/scripts/validate-pr-title.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const nlp = require('compromise');
2+
const title = process.env.PR_TITLE || '';
3+
4+
let isValidTitle = true;
5+
6+
function logSuccess(message) {
7+
console.log(`✅ ${message}`);
8+
}
9+
10+
function logFailure(message) {
11+
isValidTitle = false;
12+
console.error(`❌ ${message}`);
13+
}
14+
15+
function capitalized(string) {
16+
if (!string) return '';
17+
return string[0].toUpperCase() + string.substring(1);
18+
}
19+
20+
// Rule 1: PR title must not be empty
21+
if (title) {
22+
logSuccess(`PR title is not empty`);
23+
} else {
24+
logFailure(`PR title must not be empty`);
25+
}
26+
27+
// Rule 2: PR title must be 72 characters or less
28+
if (title.length <= 72) {
29+
logSuccess(`PR title is ${title.length} characters`);
30+
} else {
31+
logFailure(`PR title must be 72 characters or less (currently ${title.length} characters)`);
32+
}
33+
34+
// Rule 3: PR title must begin with a capital letter
35+
if (/^[A-Z]/.test(title)) {
36+
logSuccess(`PR title begins with a capital letter`);
37+
} else {
38+
logFailure('PR title must begin with a capital letter');
39+
}
40+
41+
// Rule 4: PR title must end with a letter or number
42+
if (/[A-Za-z0-9]$/.test(title)) {
43+
logSuccess(`PR title ends with a letter or number`);
44+
} else {
45+
logFailure('PR title must end with a letter or number');
46+
}
47+
48+
// Rule 5: PR title must be written in the imperative
49+
const firstWord = title.split(' ')[0];
50+
const firstWordLowercased = firstWord.toLowerCase();
51+
const firstWordCapitalized = capitalized(firstWord);
52+
const firstWordAsImperativeVerb = nlp(firstWord).verbs().toInfinitive().out('text');
53+
const firstWordAsImperativeVerbLowercased = firstWordAsImperativeVerb.toLowerCase();
54+
const firstWordAsImperativeVerbCapitalized = capitalized(firstWordAsImperativeVerb);
55+
56+
if (firstWordLowercased === firstWordAsImperativeVerbLowercased) {
57+
logSuccess(`PR title is written in the imperative`);
58+
} else if (firstWordAsImperativeVerb) {
59+
logFailure(`PR title must be written in the imperative ("${firstWordAsImperativeVerbCapitalized}" instead of "${firstWordCapitalized}")`);
60+
} else {
61+
logFailure(`PR title must begin with a verb and be written in the imperative`);
62+
}
63+
64+
if (!isValidTitle) {
65+
process.exit(1);
66+
}

.github/workflows/ci.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: CI
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
pull_request:
9+
types: [opened, reopened, synchronize]
10+
branches:
11+
- '*'
12+
13+
jobs:
14+
build-and-test:
15+
name: Build, Test, & Report Coverage
16+
runs-on: macos-latest
17+
18+
steps:
19+
- name: Checkout source code
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Xcode
23+
uses: maxim-lobanov/setup-xcode@v1
24+
with:
25+
xcode-version: latest
26+
27+
- name: Install Brewfile dependencies
28+
run: brew bundle install
29+
30+
- name: Run SwiftFormat in lint mode
31+
run: swiftformat --lint .
32+
33+
- name: Install package dependencies
34+
run: swift package resolve
35+
36+
- name: Build the package
37+
run: swift build
38+
39+
- name: Run tests with code coverage
40+
run: swift test --enable-code-coverage
41+
42+
- name: Gather code coverage
43+
run: xcrun llvm-cov export -format="lcov" .build/debug/swift-mockingPackageTests.xctest/Contents/MacOS/swift-mockingPackageTests -instr-profile .build/debug/codecov/default.profdata > coverage_report.lcov
44+
45+
- name: Upload coverage to Codecov
46+
uses: codecov/codecov-action@v5
47+
with:
48+
files: coverage_report.lcov
49+
token: ${{ secrets.CODECOV_TOKEN }}
50+
slug: fetch-rewards/swift-mocking
51+
verbose: true
52+
fail_ci_if_error: true

.github/workflows/pr-labels.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: PR Labels
2+
3+
on:
4+
pull_request:
5+
types: [opened, labeled, unlabeled, reopened, synchronize]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: read
10+
11+
jobs:
12+
check-for-required-labels:
13+
name: Check For Required Labels
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- name: Checkout source code
18+
uses: actions/checkout@v4
19+
20+
- name: Validate PR has required labels
21+
env:
22+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23+
run: |
24+
PR_NUMBER=${{ github.event.pull_request.number }}
25+
REPO=${{ github.repository }}
26+
27+
REQUIRED_LABELS=("bug" "ci/cd" "dependencies" "documentation" "enhancement" "formatting" "refactoring" "testing")
28+
LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '.labels[].name')
29+
30+
echo "PR labels:"
31+
echo "$LABELS"
32+
33+
for required in "${REQUIRED_LABELS[@]}"; do
34+
if echo "$LABELS" | grep -q "^$required$"; then
35+
echo "✅ Found required label: $required"
36+
exit 0
37+
fi
38+
done
39+
40+
echo "❌ PR is missing a required label."
41+
echo "At least one of the following labels is required:"
42+
printf '%s\n' "${REQUIRED_LABELS[@]}"
43+
exit 1
44+
shell: bash

.github/workflows/pr-title.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: PR Title
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, reopened, synchronize]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: read
10+
11+
jobs:
12+
validate-pr-title:
13+
name: Validate PR Title
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout source code
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Node.js
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: latest
23+
24+
- name: Install dependencies
25+
run: npm install compromise
26+
27+
- name: Validate PR title
28+
run: node .github/scripts/validate-pr-title.js
29+
env:
30+
PR_TITLE: ${{ github.event.pull_request.title }}

codecov.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ignore:
2+
- "Tests"

0 commit comments

Comments
 (0)