-
Notifications
You must be signed in to change notification settings - Fork 14
168 lines (151 loc) · 6.6 KB
/
Copy pathanalyze-code.yml
File metadata and controls
168 lines (151 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
name: Analyze Repositories with PAT
on:
schedule:
- cron: "0 0 * * 0"
workflow_dispatch:
permissions:
contents: write
jobs:
count-lines:
# Keep this workflow copyable without running PAT analysis in this demo repo.
if: github.repository != 'arhamkhnz/github-code-analyzer'
runs-on: ubuntu-latest
env:
# Use cloc language names. Highlighted languages get their own README row.
HIGHLIGHT_LANGS: "JavaScript,TypeScript,JSX,Vuejs Component,PHP,C#"
# These languages are excluded from the cloc total.
IGNORE_LANGS: "JSON,HTML,CSS,SCSS,Sass,Markdown,SVG,XML,YAML,TOML,CSV,Text,Properties"
steps:
- name: Checkout report repository
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Install cloc and jq
run: |
sudo apt-get update
sudo apt-get install -y cloc jq
- name: Discover repositories accessible to the PAT
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
shell: bash
run: |
set -euo pipefail
if [[ -z "$GH_TOKEN" ]]; then
echo "Add a GH_PAT repository secret before running this workflow" >&2
exit 1
fi
# The authenticated-user endpoint can include owned, collaborator,
# public, and private repositories. Fetch every page, then skip forks.
if ! gh api --paginate --slurp 'user/repos?per_page=100' > "$RUNNER_TEMP/pat-repos.json" 2>/dev/null; then
echo "Could not list repositories. Check GH_PAT access." >&2
exit 1
fi
jq -e 'type == "array" and all(.[]; type == "array")' "$RUNNER_TEMP/pat-repos.json" > /dev/null
if ! jq -e 'any(.[][]; .private == true and .fork == false)' "$RUNNER_TEMP/pat-repos.json" > /dev/null; then
echo "::warning::No private non-fork repositories were returned. Check the token's resource owner and repository access if you expected private repos."
fi
jq -r '.[][] | select(.fork == false) | .full_name' \
"$RUNNER_TEMP/pat-repos.json" > "$RUNNER_TEMP/pat-source-repos.txt"
- name: Clone default branches
env:
GH_TOKEN: ${{ secrets.GH_PAT }}
shell: bash
run: |
set -euo pipefail
gh auth setup-git --hostname github.com --force
mapfile -t repos < "$RUNNER_TEMP/pat-source-repos.txt"
clone_root="$RUNNER_TEMP/pat-code-repos"
mkdir -p "$clone_root"
for index in "${!repos[@]}"; do
repo="${repos[$index]}"
if ! git clone --quiet --depth 1 --single-branch \
"https://github.com/$repo.git" "$clone_root/$index" > /dev/null 2>&1; then
echo "A repository could not be cloned. Check GH_PAT access." >&2
exit 1
fi
done
- name: Count code lines
shell: bash
run: |
set -euo pipefail
mkdir -p output
if [[ -s "$RUNNER_TEMP/pat-source-repos.txt" ]]; then
if ! cloc "$RUNNER_TEMP/pat-code-repos" --json \
--report-file=output/cloc-output.json \
--exclude-dir=.git --exclude-lang="$IGNORE_LANGS" > /dev/null 2>&1; then
echo "Could not count code lines; no stats were published." >&2
exit 1
fi
else
jq -n '{SUM: {code: 0}}' > output/cloc-output.json
fi
jq 'del(.header)' output/cloc-output.json > "$RUNNER_TEMP/pat-cloc-summary.json"
mv "$RUNNER_TEMP/pat-cloc-summary.json" output/cloc-output.json
- name: Update PAT section in README
shell: python
run: |
import json
import os
import re
from pathlib import Path
report = json.loads(Path("output/cloc-output.json").read_text())
total = report.get("SUM", {}).get("code")
if not isinstance(total, int) or total < 0:
raise ValueError("cloc did not produce a valid code total")
languages = []
for name, counts in report.items():
if name in {"header", "SUM"}:
continue
code = counts.get("code")
if not isinstance(code, int) or code < 0:
raise ValueError(f"Invalid cloc count for {name}")
if code:
languages.append((name, code))
if sum(code for _, code in languages) != total:
raise ValueError("Language counts do not match the cloc total")
highlights = {name.strip() for name in os.environ["HIGHLIGHT_LANGS"].split(",")}
named = sorted(
((name, code) for name, code in languages if name in highlights),
key=lambda item: (-item[1], item[0]),
)
other = sum(code for name, code in languages if name not in highlights)
width = max([12, *(len(name) for name, _ in named)])
fence = chr(96) * 3
rows = [fence, "[ LANGUAGES BREAKDOWN ]", ""]
rows += [f"{name:<{width}} --> {code:,} lines" for name, code in named]
if other:
rows.append(f"{'Others':<{width}} --> {other:,} lines")
rows += ["", f"[ TOTAL LINES OF CODE: {total:,} ]", fence]
start = re.compile(r"^<!-- LANGUAGES BREAKDOWN START -->$", re.MULTILINE)
end = re.compile(r"^<!-- LANGUAGES BREAKDOWN END -->$", re.MULTILINE)
readme = Path("README.md")
content = readme.read_text()
starts = list(start.finditer(content))
ends = list(end.finditer(content))
if len(starts) != 1 or len(ends) != 1 or starts[0].end() >= ends[0].start():
raise ValueError("README must contain exactly one ordered PAT stats marker pair")
updated = (
content[: starts[0].end()]
+ "\n"
+ "\n".join(rows)
+ "\n"
+ content[ends[0].start() :]
)
if updated != content:
readme.write_text(updated)
- name: Commit changed PAT stats
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
git add README.md output/cloc-output.json
if git diff --cached --quiet; then
echo "PAT code statistics are unchanged"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -m "chore: update PAT repository code stats"
gh auth setup-git --hostname github.com --force
git push origin "HEAD:$GITHUB_REF"