Skip to content

Commit 05c79ca

Browse files
feat: add audit_repos action (#40)
1 parent dc85c31 commit 05c79ca

File tree

10 files changed

+1639
-9
lines changed

10 files changed

+1639
-9
lines changed
Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
name: Pytest
2+
name: CI Tests
33
permissions:
44
contents: write # write is required for release_setup
55

@@ -21,7 +21,7 @@ concurrency:
2121
cancel-in-progress: true
2222

2323
jobs:
24-
pytest:
24+
tests:
2525
runs-on: ${{ matrix.runner }}
2626
env:
2727
INPUT_PYTHON_VERSION: '3.12'
@@ -41,6 +41,11 @@ jobs:
4141
with:
4242
python-version: ${{ env.INPUT_PYTHON_VERSION }}
4343

44+
- name: Set up Node
45+
uses: actions/setup-node@v5
46+
with:
47+
node-version: latest
48+
4449
- name: Install Python Dependencies
4550
shell: bash
4651
run: |
@@ -49,8 +54,12 @@ jobs:
4954
-r requirements.txt \
5055
-r requirements-dev.txt
5156
57+
- name: Install Node Dependencies
58+
shell: bash
59+
run: npm install
60+
5261
- name: Test with pytest
53-
id: test
62+
id: pytest
5463
env:
5564
INPUT_GITHUB_TOKEN: ${{ github.actor == 'dependabot[bot]' && secrets.GH_BOT_TOKEN || secrets.GITHUB_TOKEN }}
5665
shell: bash
@@ -63,41 +72,64 @@ jobs:
6372
fi
6473
echo "::endgroup::"
6574
66-
echo "::group::Run Tests"
75+
echo "::group::Run Python Tests"
6776
python -m pytest \
6877
-rxXs \
6978
--tb=native \
7079
--verbose \
7180
--color=yes \
7281
--cov=actions \
73-
--junitxml=junit.xml \
82+
--cov-report=xml:coverage/python-coverage.xml \
83+
--cov-report=json:coverage/python-coverage.json \
84+
--junitxml=junit-python.xml \
7485
-o junit_family=legacy \
7586
tests
7687
echo "::endgroup::"
7788
89+
- name: Test with Jest
90+
id: jest
91+
if: >-
92+
always() &&
93+
(steps.pytest.outcome == 'success' || steps.pytest.outcome == 'failure')
94+
env:
95+
FORCE_COLOR: true
96+
shell: bash
97+
run: npm test
98+
7899
- name: Upload test results to Codecov
79100
# any except canceled or skipped
80101
if: >-
81102
always() &&
82-
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') &&
103+
(
104+
steps.pytest.outcome == 'success' ||
105+
steps.pytest.outcome == 'failure' ||
106+
steps.jest.outcome == 'success' ||
107+
steps.jest.outcome == 'failure'
108+
) &&
83109
startsWith(github.repository, 'LizardByte/')
84110
uses: codecov/test-results-action@v1
85111
with:
86112
fail_ci_if_error: true
87-
files: junit.xml
113+
files: ./junit-python.xml,./junit.xml
88114
flags: ${{ runner.os }}
89115
token: ${{ secrets.CODECOV_TOKEN }}
90116
verbose: true
91117

92-
- name: Upload coverage
118+
- name: Upload coverage to Codecov
93119
# any except canceled or skipped
94120
if: >-
95121
always() &&
96-
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') &&
122+
(
123+
steps.pytest.outcome == 'success' ||
124+
steps.pytest.outcome == 'failure' ||
125+
steps.jest.outcome == 'success' ||
126+
steps.jest.outcome == 'failure'
127+
) &&
97128
startsWith(github.repository, 'LizardByte/')
98129
uses: codecov/codecov-action@v5
99130
with:
100131
fail_ci_if_error: true
132+
files: ./coverage/python-coverage.xml,./coverage/coverage-final.json
101133
flags: ${{ runner.os }}
102134
token: ${{ secrets.CODECOV_TOKEN }}
103135
verbose: true

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,14 @@ cython_debug/
150150
# and can be added to the global gitignore or merged into this file. For a more nuclear
151151
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
152152
.idea/
153+
154+
# Node.js
155+
node_modules/
156+
npm-debug.log*
157+
yarn-debug.log*
158+
yarn-error.log*
159+
package-lock.json
160+
161+
# Jest
162+
coverage/
163+
junit.xml

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This is a monorepo containing a collection of GitHub Actions maintained by Lizar
99

1010
| Action | Description | Type | Language |
1111
|-------------------------------------------------------|----------------------------------------------|-----------|------------------|
12+
| [audit_repos](actions/audit_repos#readme) | Audit repositories in an organization | composite | javascript |
1213
| [facebook_post](actions/facebook_post#readme) | Post to Facebook page/group using Graph API | docker | python |
1314
| [monitor_space](actions/monitor_space#readme) | Monitor and track minimum free disk space | composite | bash |
1415
| [more_space](actions/more_space#readme) | Free up disk space in GitHub Actions runners | composite | bash |

actions/audit_repos/README.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# audit_repos
2+
3+
A reusable action to audit repositories in an organization or user account.
4+
5+
This action fetches repositories from an organization or user and runs various validation checks on them, including:
6+
- Repository descriptions (existence, format, length)
7+
- Repository settings (issues enabled, etc.)
8+
- Merge types (merge commits, squash, rebase)
9+
- Discussions configuration (org-wide vs. repo-specific)
10+
- Community health files (README, LICENSE, CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, sponsors)
11+
12+
## Token Requirements
13+
14+
This action works with the default `GITHUB_TOKEN` **only for public repositories in the current organization**.
15+
For full functionality, especially when auditing:
16+
- Private repositories
17+
- Repositories in a different organization
18+
- Community health files and detailed settings
19+
20+
You will need a **Personal Access Token (PAT)** with the following scopes:
21+
- `repo` (for private repositories)
22+
- `read:org` (for organization repositories)
23+
24+
## Basic Usage
25+
26+
See [action.yml](action.yml)
27+
28+
```yaml
29+
steps:
30+
- name: Audit Repositories
31+
uses: LizardByte/actions/actions/audit_repos@master
32+
with:
33+
token: ${{ secrets.GH_TOKEN }}
34+
```
35+
36+
## Inputs
37+
38+
| Name | Description | Default | Required |
39+
|-----------------------|---------------------------------------------------------------------------------|------------|----------|
40+
| token | GitHub Token with permissions to read organization repositories. | | `true` |
41+
| githubOrg | GitHub organization or user to audit. Defaults to current repo owner. | `""` | `false` |
42+
| includeArchived | Include archived repositories in the audit. | `false` | `false` |
43+
| includeForked | Include forked repositories in the audit. | `true` | `false` |
44+
| excludedRepos | Comma-separated list of repository names to exclude from the audit. | `""` | `false` |
45+
| checkDescription | Run the repository description validation check. | `true` | `false` |
46+
| allowEmptyDescription | Allow repositories to have empty descriptions when checkDescription is enabled. | `false` | `false` |
47+
| checkSettings | Run the repository settings validation check. | `true` | `false` |
48+
| checkMergeTypes | Run the merge types validation check. | `true` | `false` |
49+
| allowMergeCommit | Allow merge commits. Options: `disabled`, `enabled`, `any`. | `disabled` | `false` |
50+
| allowSquashMerge | Allow squash merge. Options: `disabled`, `enabled`, `any`. | `enabled` | `false` |
51+
| allowRebaseMerge | Allow rebase merge. Options: `disabled`, `enabled`, `any`. | `any` | `false` |
52+
| checkDiscussions | Run discussions validation. Options: `disabled`, `org`, `repo`. | `disabled` | `false` |
53+
| orgDiscussionsRepo | Repository name allowed to have discussions when using org-wide discussions. | `.github` | `false` |
54+
| checkCommunityFiles | Run the community health files validation check. | `true` | `false` |
55+
| checkReadme | Check if README exists. | `true` | `false` |
56+
| checkLicense | Check if LICENSE exists. | `true` | `false` |
57+
| checkCodeOfConduct | Check if CODE_OF_CONDUCT exists. | `true` | `false` |
58+
| checkContributing | Check if CONTRIBUTING exists. | `true` | `false` |
59+
| checkSecurity | Check if SECURITY policy exists. | `true` | `false` |
60+
| checkSponsors | Check if sponsors are activated (FUNDING.yml exists). | `true` | `false` |
61+
62+
## Outputs
63+
64+
This action does not produce outputs. It will fail the workflow if any audits fail,
65+
with detailed logs showing which repositories and checks failed.
66+
67+
## Audit Checks
68+
69+
### Repository Descriptions
70+
When `checkDescription` is enabled, the following validations are performed:
71+
- Checks if description exists (unless `allowEmptyDescription` is set to `true`)
72+
- Ensures description does not have leading or trailing whitespace
73+
- Ensures description ends with a period
74+
- Ensures description is at least 10 characters long
75+
76+
Set `allowEmptyDescription: true` to skip the missing description check while still validating format rules for repositories that do have descriptions.
77+
78+
### Repository Settings
79+
- Ensures issues are enabled
80+
81+
### Merge Types
82+
Validates merge type settings according to your preferences:
83+
- **disabled**: The merge type should be disabled
84+
- **enabled**: The merge type should be enabled
85+
- **any**: No validation (allows any setting)
86+
87+
Default configuration:
88+
- Merge commits: `disabled`
89+
- Squash merge: `enabled`
90+
- Rebase merge: `any`
91+
92+
### Discussions
93+
Validates discussions configuration:
94+
- **disabled**: Skip discussions check
95+
- **org**: Ensures repo discussions are disabled (assuming org-wide discussions)
96+
- **repo**: Ensures every repo has discussions enabled
97+
98+
> Note**: When using org-wide discussions, the repository specified in `orgDiscussionsRepo` will be allowed to have discussions even if org-wide discussions are enforced.
99+
100+
### Community Health Files
101+
Checks for the presence of community health files:
102+
- README file
103+
- LICENSE file
104+
- CODE_OF_CONDUCT file
105+
- CONTRIBUTING guidelines
106+
- SECURITY policy
107+
- Sponsors activation (FUNDING.yml in `.github/` or root)
108+
109+
Each file check can be individually enabled/disabled.
110+
111+
> **Note**: Community health metrics are not available for forked repositories via the GitHub API, so forks will skip these checks and default to passing.
112+
113+
> **Note**: FUNDING.yml is checked at both the repository level and organization level. If your organization has a `.github` repository with `FUNDING.yml`, all repositories will inherit this and pass the sponsors check unless explicitly overridden at the repository level.
114+
115+
## Example Workflows
116+
117+
### Basic - Audit Current Organization
118+
119+
```yaml
120+
name: Audit Repos
121+
permissions: {}
122+
123+
on:
124+
schedule:
125+
- cron: '00 00 * * *'
126+
workflow_dispatch:
127+
128+
jobs:
129+
audit:
130+
name: Audit Repos
131+
runs-on: ubuntu-latest
132+
steps:
133+
- name: Run repository audits
134+
uses: LizardByte/actions/actions/audit_repos@master
135+
with:
136+
token: ${{ secrets.GH_TOKEN }}
137+
```
138+
139+
### Advanced - Custom Organization with Filters
140+
141+
```yaml
142+
steps:
143+
- name: Audit Repositories
144+
uses: LizardByte/actions/actions/audit_repos@master
145+
with:
146+
token: ${{ secrets.GH_TOKEN }}
147+
githubOrg: 'MyOrgName'
148+
includeArchived: false
149+
includeForked: false
150+
excludedRepos: 'test-repo,legacy-repo,archive-me'
151+
```
152+
153+
### Custom Merge Type Configuration
154+
155+
```yaml
156+
steps:
157+
- name: Audit Merge Settings
158+
uses: LizardByte/actions/actions/audit_repos@master
159+
with:
160+
token: ${{ secrets.GH_TOKEN }}
161+
checkMergeTypes: true
162+
allowMergeCommit: disabled
163+
allowSquashMerge: enabled
164+
allowRebaseMerge: disabled
165+
```
166+
167+
### Organization-Wide Discussions
168+
169+
```yaml
170+
steps:
171+
- name: Audit Discussions
172+
uses: LizardByte/actions/actions/audit_repos@master
173+
with:
174+
token: ${{ secrets.GH_TOKEN }}
175+
checkDiscussions: org # Ensures repo discussions are disabled
176+
```
177+
178+
### Selective Community Files Checks
179+
180+
```yaml
181+
steps:
182+
- name: Audit Essential Files Only
183+
uses: LizardByte/actions/actions/audit_repos@master
184+
with:
185+
token: ${{ secrets.GH_TOKEN }}
186+
checkCommunityFiles: true
187+
checkReadme: true
188+
checkLicense: true
189+
checkCodeOfConduct: false
190+
checkContributing: false
191+
checkSecurity: true
192+
checkSponsors: false
193+
```
194+
195+
### Selective Checks Only
196+
197+
```yaml
198+
steps:
199+
- name: Check Descriptions and Community Files Only
200+
uses: LizardByte/actions/actions/audit_repos@master
201+
with:
202+
token: ${{ secrets.GH_TOKEN }}
203+
checkDescription: true
204+
checkSettings: false
205+
checkMergeTypes: false
206+
checkDiscussions: disabled
207+
checkCommunityFiles: true
208+
```
209+
210+
### Allow Empty Descriptions
211+
212+
```yaml
213+
steps:
214+
- name: Audit with Optional Descriptions
215+
uses: LizardByte/actions/actions/audit_repos@master
216+
with:
217+
token: ${{ secrets.GH_TOKEN }}
218+
checkDescription: true
219+
allowEmptyDescription: true # Allows repos without descriptions, but validates format if present
220+
```
221+
222+
## Notes
223+
224+
- **Token**: Use a PAT with appropriate permissions for full functionality. `GITHUB_TOKEN` has limited access.
225+
- **Filters**: By default, archived repositories are excluded, but forked repositories are included
226+
- **Continuity**: The action will continue running all enabled audits even if some fail, providing a complete report
227+
- **Empty Results**: If no repositories match the filters, the action will exit successfully with a warning
228+
- **Compatibility**: The action works with both GitHub organizations and user accounts
229+
- **Rate Limiting**: The action fetches detailed information for each repository,
230+
which may be rate-limited for large organizations

0 commit comments

Comments
 (0)