1- # This workflow measures the disk size of a virtual environment
2- # after installing the Bittensor SDK across multiple Python versions.
3- # It runs only when a new pull request targets the master branch,
4- # and posts a comment with the results .
1+ # This workflow measures the disk size of a virtual environment after
2+ # installing the Bittensor SDK across multiple Python versions, for both
3+ # the PR base ref and the PR head ref. It posts (or updates) a single
4+ # sticky comment on the PR comparing Before / After / Δ per Python version .
55name : Monitor SDK Requirements Size
66
77on :
88 pull_request :
9- types : [opened, labeled]
9+ types : [opened, labeled, synchronize ]
1010 branches : [master, staging]
1111
1212permissions :
1313 pull-requests : write
1414 contents : read
15- issues : write
1615
1716jobs :
1817 read-python-versions :
@@ -28,19 +27,20 @@ jobs:
2827
2928 measure-venv :
3029 needs : read-python-versions
31- if : github.event_name == 'pull_request' && github.base_ref == 'master' || contains( github.event.pull_request.labels.*.name, 'show-venv-size')
30+ if : github.event_name == 'pull_request' && ( github.base_ref == 'master' || contains(github.event.pull_request.labels.*.name, 'show-venv-size') )
3231 runs-on : ubuntu-latest
3332 strategy :
33+ fail-fast : false
3434 matrix :
3535 python-version : ${{ fromJson(needs.read-python-versions.outputs.python-versions) }}
36- outputs :
37- py310 : ${{ steps.set-output.outputs.py310 }}
38- py311 : ${{ steps.set-output.outputs.py311 }}
39- py312 : ${{ steps.set-output.outputs.py312 }}
40- py313 : ${{ steps.set-output.outputs.py313 }}
36+ ref : [base, head]
4137
4238 steps :
43- - uses : actions/checkout@v6
39+ - name : Checkout ${{ matrix.ref }}
40+ uses : actions/checkout@v6
41+ with :
42+ ref : ${{ matrix.ref == 'base' && github.event.pull_request.base.sha || github.event.pull_request.head.sha }}
43+
4444 - uses : actions/setup-python@v6
4545 with :
4646 python-version : ${{ matrix.python-version }}
@@ -53,46 +53,99 @@ jobs:
5353 pip install .
5454
5555 - name : Measure venv size
56- id : set-output
5756 run : |
5857 SIZE=$(du -sm venv | cut -f1)
59- VERSION=${{ matrix.python-version }}
60- echo "Detected size: $SIZE MB for Python $VERSION"
61- case "$VERSION" in
62- 3.10) echo "py310=$SIZE" >> $GITHUB_OUTPUT ;;
63- 3.11) echo "py311=$SIZE" >> $GITHUB_OUTPUT ;;
64- 3.12) echo "py312=$SIZE" >> $GITHUB_OUTPUT ;;
65- 3.13) echo "py313=$SIZE" >> $GITHUB_OUTPUT ;;
66- esac
58+ echo "Detected size: $SIZE MB for Python ${{ matrix.python-version }} (${{ matrix.ref }})"
59+ echo "$SIZE" > size.txt
60+
61+ - name : Upload size artifact
62+ uses : actions/upload-artifact@v4
63+ with :
64+ name : size-${{ matrix.ref }}-py${{ matrix.python-version }}
65+ path : size.txt
66+ retention-days : 1
6767
6868 comment-on-pr :
6969 needs : measure-venv
70+ if : always() && needs.measure-venv.result != 'skipped'
7071 runs-on : ubuntu-latest
7172 steps :
73+ - name : Download size artifacts
74+ uses : actions/download-artifact@v4
75+ with :
76+ path : sizes
77+ pattern : size-*
78+
7279 - name : Post venv size summary to PR
73- uses : actions/github-script@v8
80+ uses : actions/github-script@v9
7481 with :
7582 github-token : ${{ secrets.GITHUB_TOKEN }}
7683 script : |
77- const sizes = {
78- "3.10": "${{ needs.measure-venv.outputs.py310 || 'N/A' }}",
79- "3.11": "${{ needs.measure-venv.outputs.py311 || 'N/A' }}",
80- "3.12": "${{ needs.measure-venv.outputs.py312 || 'N/A' }}",
81- "3.13": "${{ needs.measure-venv.outputs.py313 || 'N/A' }}",
84+ const fs = require('fs');
85+ const path = require('path');
86+
87+ const rows = {};
88+ for (const entry of fs.readdirSync('sizes')) {
89+ const m = entry.match(/^size-(base|head)-py(.+)$/);
90+ if (!m) continue;
91+ const [, ref, version] = m;
92+ const size = parseInt(
93+ fs.readFileSync(path.join('sizes', entry, 'size.txt'), 'utf8').trim(),
94+ 10,
95+ );
96+ rows[version] ??= {};
97+ rows[version][ref] = Number.isFinite(size) ? size : null;
98+ }
99+
100+ const versions = Object.keys(rows).sort((a, b) =>
101+ a.localeCompare(b, undefined, { numeric: true }),
102+ );
103+
104+ const fmt = (n) => (n == null ? 'N/A' : `${n} MB`);
105+ const fmtDelta = (before, after) => {
106+ if (before == null || after == null) return 'N/A';
107+ const d = after - before;
108+ if (d === 0) return '0 MB';
109+ return `${d > 0 ? '+' : ''}${d} MB`;
82110 };
83111
112+ const lines = versions.map((v) => {
113+ const { base, head } = rows[v];
114+ return `| ${v} | ${fmt(base)} | ${fmt(head)} | ${fmtDelta(base, head)} |`;
115+ });
116+
117+ const marker = '<!-- venv-size-comment -->';
84118 const body = [
119+ marker,
85120 '**Bittensor SDK virtual environment sizes by Python version:**',
86121 '',
87- '```'
88- ]
89- .concat(Object.entries(sizes).map(([v, s]) => `Python ${v}: ${s} MB`))
90- .concat(['```'])
91- .join('\n');
122+ `Comparing \`${context.payload.pull_request.base.sha.slice(0, 7)}\` (before) → \`${context.payload.pull_request.head.sha.slice(0, 7)}\` (after).`,
123+ '',
124+ '| Python | Before | After | Δ |',
125+ '|---|---|---|---|',
126+ ...lines,
127+ ].join('\n');
92128
93- github.rest.issues.createComment ({
129+ const { data: comments } = await github.rest.issues.listComments ({
94130 issue_number: context.issue.number,
95131 owner: context.repo.owner,
96132 repo: context.repo.repo,
97- body
133+ per_page: 100,
98134 });
135+ const existing = comments.find((c) => c.body && c.body.includes(marker));
136+
137+ if (existing) {
138+ await github.rest.issues.updateComment({
139+ comment_id: existing.id,
140+ owner: context.repo.owner,
141+ repo: context.repo.repo,
142+ body,
143+ });
144+ } else {
145+ await github.rest.issues.createComment({
146+ issue_number: context.issue.number,
147+ owner: context.repo.owner,
148+ repo: context.repo.repo,
149+ body,
150+ });
151+ }
0 commit comments