Skip to content

Commit 7f10104

Browse files
committed
Updated the GitHub workflows and/or the README file to the latest versions.
1 parent fad881e commit 7f10104

File tree

4 files changed

+303
-3
lines changed

4 files changed

+303
-3
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,30 @@ env:
5757
]}'
5858

5959
jobs:
60+
Redundancy-Check:
61+
runs-on: ubuntu-latest
62+
outputs:
63+
redundant: ${{ steps.check.outputs.redundant }}
64+
steps:
65+
- name: Check if this branch is a part of a PR
66+
id: check
67+
if: github.event_name != 'pull_request'
68+
run: |
69+
import requests
70+
import os
71+
import json
72+
headers = {'Authorization': 'token ' + '${{ secrets.GITHUB_TOKEN }}'}
73+
prs = requests.get("https://api.github.com/repos/${{ github.repository }}/pulls?head=${{ github.repository_owner }}:${{ github.ref_name }}",
74+
headers = headers)
75+
if len(prs.json()) > 0: open(os.getenv("GITHUB_OUTPUT"), 'a').write("redundant=1\n")
76+
shell: python
77+
6078
Set-Matrix-Private:
6179
runs-on: ubuntu-latest
80+
81+
needs: Redundancy-Check
82+
if: needs.Redundancy-Check.outputs.redundant == false
83+
6284
outputs:
6385
matrix: ${{ steps.set-matrix.outputs.matrix }}
6486
steps:
@@ -108,7 +130,7 @@ jobs:
108130
R-CMD-check:
109131
needs: Set-Matrix-Private
110132

111-
if: needs.Set-Matrix-Private.outputs.matrix != ''
133+
if: needs.Set-Matrix-Private.outputs.matrix != false
112134

113135
runs-on: ${{ matrix.config.os }}
114136

@@ -252,7 +274,7 @@ jobs:
252274
fi
253275
fi
254276
shell: bash
255-
277+
256278
- name: Upload check results
257279
if: contains(matrix.config.flags, 'covr') == false && failure()
258280
uses: actions/upload-artifact@v4
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import re
2+
from operator import add
3+
from collections import defaultdict
4+
import sys
5+
6+
HEAD_RE = re.compile("^(?P<t>[@+ -])(@ *-(?P<s>[0-9]+))?")
7+
8+
class LineMapper:
9+
def __init__(self, patch):
10+
matches = [HEAD_RE.match(line) for line in patch.split('\n')]
11+
starts = [int(m['s']) for m in matches if m['t'] == '@']
12+
lines = ''.join([m['t'] for m in matches[1:]]).split('@')
13+
lens = [len(l) for l in lines]
14+
ends = list(map(add, starts, lens))
15+
16+
self.lmap = [0] * max(ends)
17+
18+
pos1 = 0
19+
pos2 = 0
20+
21+
for ch in range(len(starts)):
22+
gap = starts[ch] - pos1 - 1
23+
self.lmap[pos1:(pos1 + gap)] = range(pos2 + 1, pos2 + gap + 1)
24+
25+
pos1 = pos1 + gap
26+
pos2 = pos2 + gap
27+
28+
for d in lines[ch]:
29+
if d in [' ', '-']: pos1 += 1
30+
if d in [' ', '+']: pos2 += 1
31+
if d == ' ': self.lmap[pos1 - 1] = pos2
32+
33+
gap = len(self.lmap) - pos1
34+
self.lmap[pos1:(pos1 + gap)] = range(pos2 + 1, pos2 + gap + 1)
35+
36+
self.shift = pos2 - pos1
37+
38+
def __getitem__(self, key):
39+
if key == 0: return 0
40+
elif key <= len(self.lmap): return self.lmap[key - 1]
41+
else: return key + self.shift
42+
43+
def chunk(l, each):
44+
for i in range(0, len(l), each):
45+
yield l[i:i+each]
46+
47+
def split_lines(lines, prefix, each = 10): # 10 = GitHub max per step.
48+
for i, l in enumerate(chunk(lines, each)):
49+
open(prefix + str(i + 1) + '.txt', 'w').writelines(l)
50+
51+
def split_by_file(lines, file_regex):
52+
o = defaultdict(list)
53+
for l in lines:
54+
f = file_regex.match(l)['file']
55+
o[f].append(l)
56+
57+
return dict(o)
58+
59+
def split_patch_by_file(patch):
60+
patch = patch.split('\n')
61+
o = {}
62+
f = None
63+
64+
for l in patch:
65+
if l.startswith('diff'):
66+
parts = l.strip().split()
67+
# The file name is usually after 'b/' (the new file)
68+
for part in parts:
69+
if part.startswith('b/'):
70+
f = part[2:]
71+
else:
72+
o[f] += l + '\n'
73+
74+
return dict(o)
75+
76+
def uniq_messages(old, new):
77+
return [msg for msg in new if msg not in set(old)]
78+
79+
def remap_file_messages(old, patch, line_regex, line_replace):
80+
m = LineMapper(patch)
81+
ol = [int(line_regex.match(l)['line']) for l in old]
82+
nl = [m[l] for l in ol]
83+
84+
return list(map(line_replace, old, ol, nl))
85+
86+
def filter_messages(old, new, patch_dict, message_regex, line_replace):
87+
old = split_by_file(old, message_regex)
88+
new = split_by_file(new, message_regex)
89+
90+
o = []
91+
for f in new.keys() & patch_dict.keys():
92+
oldnew = remap_file_messages(old.get(f, []), patch_dict[f], message_regex, line_replace)
93+
o.extend(uniq_messages(oldnew, new[f]))
94+
95+
return o
96+
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
2+
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
3+
on: [push, pull_request]
4+
5+
name: lint-changed-warnings
6+
7+
permissions: read-all
8+
9+
jobs:
10+
redundancy-check:
11+
runs-on: ubuntu-latest
12+
outputs:
13+
redundant: ${{ steps.check.outputs.redundant }}
14+
steps:
15+
- name: Check if this branch is a part of a PR
16+
id: check
17+
if: github.event_name != 'pull_request'
18+
run: |
19+
import requests
20+
import os
21+
import json
22+
headers = {'Authorization': 'token ' + '${{ secrets.GITHUB_TOKEN }}'}
23+
prs = requests.get("https://api.github.com/repos/${{ github.repository }}/pulls?head=${{ github.repository_owner }}:${{ github.ref_name }}",
24+
headers = headers)
25+
if len(prs.json()) > 0: open(os.getenv("GITHUB_OUTPUT"), 'a').write("redundant=1\n")
26+
shell: python
27+
28+
lint-changed-warnings:
29+
needs: redundancy-check
30+
if: needs.redundancy-check.outputs.redundant == false
31+
runs-on: ubuntu-latest
32+
env:
33+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
34+
steps:
35+
- name: Check out HEAD
36+
uses: actions/checkout@v4
37+
with:
38+
path: head
39+
40+
- name: Select BASE
41+
run: |
42+
if [[ ${{ github.event_name }} == "pull_request" ]]
43+
then # PR -> base branch
44+
echo "BASEREF=${{ github.event.pull_request.base.ref }}" >> "$GITHUB_ENV"
45+
elif [[ ${{ github.ref_name }} == ${{ github.event.repository.default_branch }} ]]
46+
then # default branch -> previous push
47+
echo "BASEREF=${{ github.event.before }}" >> "$GITHUB_ENV"
48+
else # otherwise -> default branch
49+
echo "BASEREF=${{ github.event.repository.default_branch }}" >> "$GITHUB_ENV"
50+
fi
51+
52+
- name: Obtain the diff for PR
53+
if: github.event_name == 'pull_request'
54+
run: |
55+
import requests
56+
import json
57+
headers = {'Authorization': 'token ' + '${{ secrets.GITHUB_TOKEN }}'}
58+
files = requests.get("https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files", headers = headers)
59+
open('diff.json', 'w').write(files.text)
60+
open('files.list', 'w').write('\n'.join([f['filename'] for f in files.json()]))
61+
shell: python
62+
63+
- name: Obtain the diff for other push
64+
if: github.event_name != 'pull_request'
65+
run: |
66+
import requests
67+
import json
68+
headers = {'Authorization': 'token ' + '${{ secrets.GITHUB_TOKEN }}'}
69+
diff = requests.get("https://api.github.com/repos/${{ github.repository }}/compare/${{ env.BASEREF }}...${{ github.ref_name }}", headers = headers)
70+
json.dump(diff.json()['files'], open('diff.json', 'w'))
71+
open('files.list', 'w').write('\n'.join([f['filename'] for f in diff.json()['files']]))
72+
shell: python
73+
74+
- name: Check out BASE
75+
uses: actions/checkout@v4
76+
with:
77+
path: base
78+
ref: ${{ env.BASEREF }}
79+
80+
- uses: r-lib/actions/setup-r@v2
81+
82+
- uses: r-lib/actions/setup-r-dependencies@v2
83+
with:
84+
extra-packages: |
85+
any::lintr
86+
needs: check
87+
working-directory: head
88+
89+
- name: Add lintr options
90+
run: |
91+
cat('\noptions(lintr.linter_file = ".lintr")\n', file = "~/.Rprofile", append = TRUE)
92+
shell: Rscript {0}
93+
94+
- name: Lint both versions
95+
run: |
96+
files <- scan("files.list", character(), sep = "\n")
97+
base_files <- list.files("base", recursive = TRUE)
98+
base_exclude <- setdiff(base_files, files)
99+
base <- lintr::lint_package("base", exclusions = base_exclude)
100+
writeLines(capture.output(base), "lintr.base.txt")
101+
102+
head_files <- list.files("head", recursive = TRUE)
103+
head_exclude <- setdiff(head_files, files)
104+
head <- lintr::lint_package("head", exclusions = head_exclude)
105+
writeLines(capture.output(head), "lintr.head.txt")
106+
shell: Rscript {0}
107+
env:
108+
LINTR_ERROR_ON_LINT: false
109+
110+
- name: Run cpplint
111+
run: |
112+
set +e
113+
pipx run cpplint --version
114+
pipx run cpplint --recursive base 2> cpplint.base.txt
115+
pipx run cpplint --recursive head 2> cpplint.head.txt
116+
set -e
117+
118+
# The first -e deletes base/ and head/ from the file path, the
119+
# second rearranges the message into GitHub's format.
120+
sed -i -r -e 's!^[^/]+/!!' -e 's!^([^:]+):([0-9]+):!::warning file=\1,line=\2::!' cpplint.base.txt cpplint.head.txt
121+
122+
- name: Save only unique warnings
123+
run: |
124+
import json
125+
import re
126+
import sys
127+
import os.path
128+
sys.path.append(os.path.join('head', '.github', 'workflows'))
129+
from changed_warnings import filter_messages, split_lines
130+
131+
patches = {f['filename']:f['patch'] for f in json.load(open('diff.json'))}
132+
133+
lintr_re = re.compile('^::warning file=(?P<file>.+),line=(?P<line>[0-9]+),col=(?P<col>[0-9]+)::')
134+
o = filter_messages(open("lintr.base.txt"), open("lintr.head.txt"), patches,
135+
lintr_re, lambda l, o, n: l.replace(f',line={o},', f',line={n},'))
136+
split_lines(o, 'lintr-')
137+
138+
cpplint_re = re.compile('^::warning file=(?P<file>.+),line=(?P<line>[0-9]+)::')
139+
o = filter_messages(open("cpplint.base.txt"), open("cpplint.head.txt"), patches,
140+
cpplint_re, lambda l, o, n: l.replace(f',line={o}::', f',line={n}::'))
141+
split_lines(o, 'cpplint-')
142+
shell: python
143+
144+
- name: Print lintr warnings 1
145+
if: ${{ hashFiles('lintr-1.txt') != '' }}
146+
run: cat "lintr-1.txt"
147+
148+
- name: Print lintr warnings 2
149+
if: ${{ hashFiles('lintr-2.txt') != '' }}
150+
run: cat "lintr-2.txt"
151+
152+
- name: Print lintr warnings 3
153+
if: ${{ hashFiles('lintr-3.txt') != '' }}
154+
run: cat "lintr-3.txt"
155+
156+
- name: Print lintr warnings 4
157+
if: ${{ hashFiles('lintr-4.txt') != '' }}
158+
run: cat "lintr-4.txt"
159+
160+
- name: Print lintr warnings 5
161+
if: ${{ hashFiles('lintr-5.txt') != '' }}
162+
run: cat "lintr-5.txt"
163+
164+
- name: Print cpplint warnings 1
165+
if: ${{ hashFiles('cpplint-1.txt') != '' }}
166+
run: cat "cpplint-1.txt"
167+
168+
- name: Print cpplint warnings 2
169+
if: ${{ hashFiles('cpplint-2.txt') != '' }}
170+
run: cat "cpplint-2.txt"
171+
172+
- name: Print cpplint warnings 3
173+
if: ${{ hashFiles('cpplint-3.txt') != '' }}
174+
run: cat "cpplint-3.txt"
175+
176+
- name: Print cpplint warnings 4
177+
if: ${{ hashFiles('cpplint-4.txt') != '' }}
178+
run: cat "cpplint-4.txt"
179+
180+
- name: Print cpplint warnings 5
181+
if: ${{ hashFiles('cpplint-5.txt') != '' }}
182+
run: cat "cpplint-5.txt"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ A set of binaries is built after every commit to the repository. We strongly enc
2626

2727
You will need to extract the MacOS `.tgz` or the Windows `.zip` file from the outer `.zip` file before installing. These binaries are usually built under the latest version of R and their operating system and may not work under other versions.
2828

29-
You may also want to install the corresponding latest binaries for packages on which `ergm` depends, in particular [`statnet.common`](https://github.com/statnet/statnet.common) and [`ergm.count`](https://github.com/statnet/ergm.count).
29+
You may also want to install the corresponding latest binaries for packages on which `ergm` depends, in particular [`statnet.common`](https://github.com/statnet/statnet.common), [`ergm.count`](https://github.com/statnet/ergm.count), and [`roxygen2`](https://github.com/krivit/roxygen2).

0 commit comments

Comments
 (0)