Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,13 +329,13 @@ Instead of hand-maintaining the repo list, a repolist file can define
puppetsync::repos_source:
org: simp
include: ['pupmod-*', 'puppet-*', 'rubygem-*'] # name globs
include_forks: # forks the org maintains
- rubygem-simp-rspec-puppet-facts
- pupmod-voxpupuli-selinux
```

* Archived and empty repos are excluded; forks are excluded unless they
match `include_forks`
* Archived and empty repos are excluded
* Repos with **issues or pull requests disabled** are excluded: the org
disables both on every fork that exists only as a mirror, so those flags
separate maintained repos (forks included) from mirrors — no fork
allow-list needed
* Repos with the `puppetsync-ignore` GitHub topic are excluded — set the
topic to opt a repo out without touching puppetsync
* Each repo's branch comes from the API's default branch (so e.g.
Expand Down
21 changes: 12 additions & 9 deletions data/sync/repolists/github-org.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
# Filtering notes:
# - Archived repos and empty repos are always excluded (exclude_archived
# defaults to true)
# - Forks are excluded unless listed in include_forks — the escape hatch
# for forks the org actively maintains
# - Repos with issues OR pull requests disabled are excluded: the org
# disables both on every fork that exists only as a mirror, so those
# two flags are the signal separating maintained repos (forks
# included) from mirrors — no fork allow-list needed
# - Repos with the 'puppetsync-ignore' topic are excluded by default: set
# that topic on a repo in GitHub to opt it out without touching this file
# - Names are matched with globs; project_type filtering (the config's
Expand All @@ -22,10 +24,11 @@ puppetsync::repos_source:
- 'pupmod-*'
- 'puppet-*'
- 'rubygem-*'
exclude: []
# Forks that simp actively maintains:
# (pupmod-voxpupuli-selinux is deliberately absent for now: its CI isn't
# green yet, and puppetsync can't open PRs from a fork-network sibling
# like silug/puppet-selinux until simp/puppetsync#83 is fixed)
include_forks:
- rubygem-simp-rspec-puppet-facts
exclude:
# Not ready for puppetsync yet: CI isn't green, and the GitHub PR
# stages can't use a fork-network sibling like silug/puppet-selinux
# until simp/puppetsync#83 is fixed
- pupmod-voxpupuli-selinux
# Never received the new baseline, and likely to be archived soon
# (archival will make this entry redundant)
- pupmod-simp-haveged
29 changes: 16 additions & 13 deletions dist/puppetsync/tasks/list_github_repos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
# Filtering (all driven by the `source` parameter):
#
# - Archived repos are excluded (`exclude_archived`, default true)
# - Forks are excluded (`exclude_forks`, default true) UNLESS the repo
# matches an `include_forks` glob — the escape hatch for forks the org
# actively maintains (e.g. rubygem-simp-rspec-puppet-facts,
# pupmod-voxpupuli-selinux)
# - Repos with issues OR pull requests DISABLED are excluded:
# puppetsync's whole output is a PR, and the simp org disables
# issues+PRs on every fork that exists only as a mirror — so either
# flag being off separates mirrors from maintained repos (forks
# included). (The old `exclude_forks`/`include_forks` allow-list is
# retired.)
# - Repos with any topic in `exclude_topics` are excluded (default:
# ['puppetsync-ignore'] — set that topic on a repo in GitHub to opt it
# out without touching puppetsync)
Expand Down Expand Up @@ -79,24 +81,25 @@ def select_repos(repos, source)
include_topics = source.fetch('include_topics', nil) || []
exclude_topics = source.fetch('exclude_topics', nil) || ['puppetsync-ignore']
exclude_archived = source.fetch('exclude_archived', true)
exclude_forks = source.fetch('exclude_forks', true)
include_forks = source.fetch('include_forks', nil) || []
if source.key?('exclude_forks') || source.key?('include_forks')
warn '== WARNING: exclude_forks/include_forks are retired and ignored — ' \
'inventory now includes any repo with issues+PRs enabled ' \
'(mirrors have them disabled org-wide)'
end

repos.select do |repo|
name = repo['name']
topics = repo['topics'] || []
next false if exclude_archived && repo['archived']
next false if repo['size'].to_i.zero?
# puppetsync's whole output is a PR; a repo with PRs (or issues)
# disabled is a mirror (the org turns both off on mirror forks).
# Absent fields => include, so older API responses/fixtures don't
# silently empty the inventory.
next false unless repo.fetch('has_pull_requests', true) && repo.fetch('has_issues', true)
next false if glob_match?(name, exclude_globs)
next false if topics.any? { |topic| exclude_topics.include?(topic) }

# A fork listed in include_forks is an explicit allow-list entry: it
# both clears the fork gate AND bypasses the include filters below
# (listing it means "I want this fork", whatever its name)
explicitly_included_fork = repo['fork'] && glob_match?(name, include_forks)
next false if repo['fork'] && exclude_forks && !explicitly_included_fork
next true if explicitly_included_fork

glob_match?(name, include_globs) || topics.any? { |topic| include_topics.include?(topic) }
end
end
Expand Down
83 changes: 49 additions & 34 deletions spec/tasks/list_github_repos_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,41 @@
let(:org_repos) do
[
{ 'name' => 'pupmod-simp-aide', 'full_name' => 'simp/pupmod-simp-aide',
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 500 },
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 500,
'has_issues' => true, 'has_pull_requests' => true },
{ 'name' => 'puppet-gpasswd', 'full_name' => 'simp/puppet-gpasswd',
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 200 },
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 200,
'has_issues' => true, 'has_pull_requests' => true },
{ 'name' => 'pupmod-simp-ntpd', 'full_name' => 'simp/pupmod-simp-ntpd',
'fork' => false, 'archived' => true, 'default_branch' => 'master', 'topics' => [], 'size' => 300 },
'fork' => false, 'archived' => true, 'default_branch' => 'master', 'topics' => [], 'size' => 300,
'has_issues' => true, 'has_pull_requests' => true },
# Maintained forks: issues + PRs enabled
{ 'name' => 'rubygem-simp-rspec-puppet-facts', 'full_name' => 'simp/rubygem-simp-rspec-puppet-facts',
'fork' => true, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 100 },
'fork' => true, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 100,
'has_issues' => true, 'has_pull_requests' => true },
{ 'name' => 'pupmod-voxpupuli-selinux', 'full_name' => 'simp/pupmod-voxpupuli-selinux',
'fork' => true, 'archived' => false, 'default_branch' => 'simp-master', 'topics' => [], 'size' => 400 },
'fork' => true, 'archived' => false, 'default_branch' => 'simp-master', 'topics' => [], 'size' => 400,
'has_issues' => true, 'has_pull_requests' => true },
# Mirror fork: issues + PRs disabled org-wide
{ 'name' => 'puppetlabs-apache', 'full_name' => 'simp/puppetlabs-apache',
'fork' => true, 'archived' => false, 'default_branch' => 'main', 'topics' => [], 'size' => 900 },
'fork' => true, 'archived' => false, 'default_branch' => 'main', 'topics' => [], 'size' => 900,
'has_issues' => false, 'has_pull_requests' => false },
# Only ONE of the two flags off still means mirror-ish: skip
{ 'name' => 'pupmod-simp-halfmirror', 'full_name' => 'simp/pupmod-simp-halfmirror',
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 70,
'has_issues' => false, 'has_pull_requests' => true },
{ 'name' => 'pupmod-simp-optout', 'full_name' => 'simp/pupmod-simp-optout',
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => ['puppetsync-ignore'], 'size' => 100 },
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => ['puppetsync-ignore'], 'size' => 100,
'has_issues' => true, 'has_pull_requests' => true },
{ 'name' => 'topic-tagged-tool', 'full_name' => 'simp/topic-tagged-tool',
'fork' => false, 'archived' => false, 'default_branch' => 'main', 'topics' => ['simp-baseline'], 'size' => 50 },
'fork' => false, 'archived' => false, 'default_branch' => 'main', 'topics' => ['simp-baseline'], 'size' => 50,
'has_issues' => true, 'has_pull_requests' => true },
# No flags at all (older API shape): must still be included
{ 'name' => 'pupmod-simp-legacyfields', 'full_name' => 'simp/pupmod-simp-legacyfields',
'fork' => false, 'archived' => false, 'default_branch' => 'master', 'topics' => [], 'size' => 60 },
{ 'name' => 'empty-repo', 'full_name' => 'simp/empty-repo',
'fork' => false, 'archived' => false, 'default_branch' => 'main', 'topics' => [], 'size' => 0 },
'fork' => false, 'archived' => false, 'default_branch' => 'main', 'topics' => [], 'size' => 0,
'has_issues' => true, 'has_pull_requests' => true },
]
end

Expand All @@ -35,47 +53,42 @@ def urls(result)
result['repos_config'].keys
end

it 'excludes archived repos, forks, empty and opted-out repos by default' do
it 'includes maintained forks and excludes mirrors, archived, empty, and opted-out repos by default' do
result = run_list({ 'org' => 'simp' })

expect(urls(result)).to contain_exactly(
'https://github.com/simp/pupmod-simp-aide',
'https://github.com/simp/puppet-gpasswd',
'https://github.com/simp/topic-tagged-tool',
# forks with issues+PRs enabled are maintained repos, not mirrors
'https://github.com/simp/rubygem-simp-rspec-puppet-facts',
'https://github.com/simp/pupmod-voxpupuli-selinux',
# missing flags (older API shape) must not exclude
'https://github.com/simp/pupmod-simp-legacyfields',
)
end

it 'keeps forks matching include_forks (the maintained-fork exceptions)' do
result = run_list(
'org' => 'simp',
'include_forks' => ['rubygem-simp-rspec-puppet-facts', 'pupmod-voxpupuli-selinux'],
)
it 'skips a repo when EITHER issues or pull requests are disabled' do
result = run_list({ 'org' => 'simp' })

expect(urls(result)).to include(
'https://github.com/simp/rubygem-simp-rspec-puppet-facts',
'https://github.com/simp/pupmod-voxpupuli-selinux',
)
expect(urls(result)).not_to include('https://github.com/simp/puppetlabs-apache')
expect(urls(result)).not_to include('https://github.com/simp/puppetlabs-apache') # both off
expect(urls(result)).not_to include('https://github.com/simp/pupmod-simp-halfmirror') # issues off
end

it 'include_forks alone suffices: listed forks bypass the include globs' do
# Mirrors the shipped github-org.yaml shape, but with include globs that
# do NOT match one of the fork exceptions
result = run_list(
'org' => 'simp',
'include' => ['pupmod-*'],
'include_forks' => ['rubygem-simp-rspec-puppet-facts'],
)
it 'warns that the retired include_forks/exclude_forks keys are ignored' do
stdout, stderr, status = run_task('list_github_repos.rb',
'source' => { 'org' => 'simp', 'include_forks' => ['x'] }, 'repos' => org_repos)

expect(urls(result)).to include('https://github.com/simp/rubygem-simp-rspec-puppet-facts')
expect(urls(result)).not_to include('https://github.com/simp/puppet-gpasswd') # non-fork still needs include
expect(status).to be_success, stderr
expect(stderr).to include('retired and ignored')
# ...and they really are ignored: mirrors stay out, maintained forks stay in
result = JSON.parse(stdout)
expect(result['repos_config'].keys).to include('https://github.com/simp/pupmod-voxpupuli-selinux')
expect(result['repos_config'].keys).not_to include('https://github.com/simp/puppetlabs-apache')
end

it 'takes each branch from the API default_branch' do
result = run_list(
'org' => 'simp',
'include_forks' => ['pupmod-voxpupuli-selinux'],
)
result = run_list({ 'org' => 'simp' })

expect(result['repos_config']['https://github.com/simp/pupmod-voxpupuli-selinux']).to eq('branch' => 'simp-master')
expect(result['repos_config']['https://github.com/simp/pupmod-simp-aide']).to eq('branch' => 'master')
Expand All @@ -87,6 +100,8 @@ def urls(result)
expect(urls(result)).to contain_exactly(
'https://github.com/simp/pupmod-simp-aide',
'https://github.com/simp/puppet-gpasswd',
'https://github.com/simp/pupmod-voxpupuli-selinux',
'https://github.com/simp/pupmod-simp-legacyfields',
)
end

Expand Down