Skip to content

Commit 0b9305f

Browse files
authored
Merge branch 'main' into main
2 parents a786924 + c02dcfa commit 0b9305f

File tree

10 files changed

+151
-0
lines changed

10 files changed

+151
-0
lines changed

.github/workflows/lint.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- uses: actions/checkout@v6.0.1
17+
with:
18+
ref: ${{ github.event.pull_request.head.ref || github.ref }}
1719

1820
- name: Setup Ruby
1921
uses: ruby/setup-ruby@v1.284.0

.github/workflows/test.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ jobs:
5858
with:
5959
bundler-cache: true
6060

61+
- name: Restore API cache
62+
if: |
63+
(matrix.test_type == 'collections' && steps.collections.outputs.changed) ||
64+
(matrix.test_type == 'all' && steps.all.outputs.changed)
65+
uses: actions/cache@v4
66+
with:
67+
path: .api-cache.json
68+
key: api-cache-${{ matrix.test_type }}-${{ github.run_id }}
69+
restore-keys: |
70+
api-cache-${{ matrix.test_type }}-
71+
6172
- name: Build and test with Rake
6273
if: |
6374
(matrix.test_type == 'topics' && steps.topics.outputs.changed) ||
@@ -69,5 +80,6 @@ jobs:
6980
TOPIC_FILES: ${{ steps.topics.outputs.changed }}
7081
COLLECTION_FILES: ${{ steps.collections.outputs.changed }}
7182
TEST_ALL_FILES: ${{ steps.all.outputs.changed }}
83+
SKIP_COLLECTION_API_CHECKS: ${{ matrix.test_type == 'all' && '1' || '' }}
7284
COLLECTION_SHARD: ${{ matrix.shard }}
7385
COLLECTION_TOTAL_SHARDS: ${{ matrix.total_shards }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ vendor
88
.bundle
99
.idea
1010
.tool-versions
11+
.api-cache.json

test/collections_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@
137137
end
138138

139139
it "fails if a user, organization, or repository has been renamed or removed" do
140+
if ENV["SKIP_COLLECTION_API_CHECKS"]
141+
skip "Skipping collection API checks (rename detection handled by collections-renames)"
142+
end
143+
140144
errors = []
141145
repos_to_check = []
142146
users_to_check = []

test/test_helper.rb

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,97 @@ def add_message(type, file, line_number, message)
270270
client.messages << "::#{type} file=#{file},line=#{line_number}::#{message}"
271271
end
272272

273+
CACHE_FILE = File.expand_path("../.api-cache.json", __dir__)
274+
CACHE_TTL_SECONDS = 24 * 60 * 60 # 24 hours
275+
276+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
277+
def load_api_cache!
278+
return unless File.exist?(CACHE_FILE)
279+
280+
data = JSON.parse(File.read(CACHE_FILE))
281+
now = Time.now.to_i
282+
ttl = CACHE_TTL_SECONDS
283+
284+
data["repos"]&.each do |key, entry|
285+
cached_at = entry["cached_at"]
286+
next unless cached_at
287+
next if now - cached_at.to_i > ttl
288+
289+
result = entry["value"]
290+
# Reconstruct a minimal object that responds to .full_name
291+
cached = if result.nil?
292+
nil
293+
else
294+
next unless result["full_name"]
295+
296+
Struct.new(:full_name).new(result["full_name"])
297+
end
298+
NewOctokit.class_variable_get(:@@repos)[key] = cached
299+
end
300+
301+
data["users"]&.each do |key, entry|
302+
cached_at = entry["cached_at"]
303+
next unless cached_at
304+
next if now - cached_at.to_i > ttl
305+
306+
result = entry["value"]
307+
cached = if result.nil?
308+
nil
309+
else
310+
next unless result["login"]
311+
312+
Struct.new(:login).new(result["login"])
313+
end
314+
NewOctokit.class_variable_get(:@@users)[key] = cached
315+
end
316+
rescue StandardError => error
317+
warn "Failed to load API cache: #{error.message}"
318+
end
319+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
320+
321+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
322+
def save_api_cache!
323+
now = Time.now.to_i
324+
repos_data = {}
325+
users_data = {}
326+
327+
NewOctokit.class_variable_get(:@@repos).each do |key, value|
328+
next if key == :skip_requests
329+
next if value == true
330+
331+
repos_data[key.to_s] = {
332+
"cached_at" => now,
333+
"value" => if value.nil?
334+
nil
335+
else
336+
{ "full_name" => value.respond_to?(:full_name) ? value.full_name : value.to_s }
337+
end,
338+
}
339+
end
340+
341+
NewOctokit.class_variable_get(:@@users).each do |key, value|
342+
next if key == :skip_requests
343+
next if value == true
344+
345+
users_data[key.to_s] = {
346+
"cached_at" => now,
347+
"value" => if value.nil?
348+
nil
349+
else
350+
{ "login" => value.respond_to?(:login) ? value.login : value.to_s }
351+
end,
352+
}
353+
end
354+
355+
File.write(CACHE_FILE, JSON.pretty_generate({ "repos" => repos_data, "users" => users_data }))
356+
rescue StandardError => error
357+
warn "Failed to save API cache: #{error.message}"
358+
end
359+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
360+
361+
# Load cached API results at startup
362+
load_api_cache!
363+
273364
Minitest.after_run do
274365
warn "Repo checks were rate limited during this CI run" if NewOctokit.repos_skipped?
275366
warn "User checks were rate limited during this CI run" if NewOctokit.users_skipped?
@@ -279,4 +370,7 @@ def add_message(type, file, line_number, message)
279370
NewOctokit.messages.each do |message|
280371
puts message
281372
end
373+
374+
# Persist cache for next CI run
375+
save_api_cache!
282376
end

topics/ai-marketing/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
aliases: marketing-ai, ai-in-marketing, ai-for-marketing, marketing-with-ai
3+
display_name: AI marketing
4+
short_description: AI marketing uses artificial intelligence concepts and models to achieve marketing goals.
5+
topic: ai-marketing
6+
related: marketing-automation, machine-learning, ai-agents, natural-language-processing, seo, content-generation, digital-marketing, llm, generative-ai
7+
wikipedia_url: https://en.wikipedia.org/wiki/Marketing_and_artificial_intelligence
8+
---
9+
AI marketing is a form of marketing that uses artificial intelligence concepts and models such as machine learning, natural language processing, and computer vision to achieve marketing goals. It automates decision-making processes across marketing functions including research, content creation, search optimization, advertising, and campaign management. The field is evolving from AI-assisted tools toward autonomous AI agents that can research, decide, and execute across marketing workflows.

topics/data-space/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
aliases: dataspace, dataspaces, data-spaces
3+
display_name: Data Space
4+
related: data-sovereignty, data-sharing, interoperability, dataeconomy, dataexchange, dcat, dcat-ap, cybersecurity
5+
short_description: A data space is a federated ecosystem enabling secure, sovereign, and interoperable data sharing.
6+
topic: data-space
7+
wikipedia_url: https://en.wikipedia.org/wiki/Dataspace
8+
---
9+
A **data space** is a decentralized, federated infrastructure that facilitates the secure and trustworthy exchange of data between multiple participants. Unlike centralized data lakes or platforms, a data space preserves **data sovereignty**, meaning the data owner retains complete control over who can access their data and under what conditions. It relies on common governance frameworks, shared standards, interoperability protocols, and trust services to enable a fair and competitive data economy.

topics/discord-bot/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
display_name: Discord bot
3+
short_description: Programmable agents that automate tasks and provide interactive features within Discord servers.
4+
topic: discord-bot
5+
wikipedia_url: https://en.wikipedia.org/wiki/Discord_(software)
6+
---
7+
Discord bots are automated programs that interact with users on the Discord communication platform. Built using various APIs and libraries—such as discord.js, discord.py, or JDA—these bots can perform a wide range of functions, from server moderation and music playback to complex integrations with external web services and games.

topics/mruby/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
created_by: Yukihiro Matsumoto
3+
display_name: mruby
4+
github_url: https://github.com/mruby
5+
logo: mruby.png
6+
related: language, mrubyc, microcontroller, ruby
7+
released: April 20, 2012
8+
short_description: mruby is a lightweight, embeddable implementation of Ruby.
9+
topic: mruby
10+
url: https://mruby.org/
11+
wikipedia_url: https://en.wikipedia.org/wiki/Mruby
12+
---
13+
mruby is the lightweight implementation of the Ruby language complying with part of the [ISO standard](https://www.iso.org/standard/59579.html). It can be linked and embedded within applications and it's designed to run in constrained environments, like microcontrollers.

topics/mruby/mruby.png

23.7 KB
Loading

0 commit comments

Comments
 (0)