Skip to content

Commit 380b40f

Browse files
committed
Merge main; re-add gno-explorer
2 parents a6244eb + a3c5b85 commit 380b40f

2 files changed

Lines changed: 112 additions & 0 deletions

File tree

.github/workflows/pr-summary.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: pr-summary
2+
3+
# Posts (and keeps updating) a single sticky comment summarizing what a PR
4+
# changes in the list: entries added/removed, their section, and a live link
5+
# check. Informational only — the awesome-lint and link-check jobs remain the
6+
# authoritative gate.
7+
#
8+
# Uses pull_request_target so it has permission to comment on PRs from forks.
9+
# It NEVER checks out or executes the PR's code: it only reads the diff and the
10+
# head README.md through the API and performs outbound HTTP checks on the URLs.
11+
12+
on:
13+
pull_request_target:
14+
types: [opened, synchronize, reopened]
15+
16+
permissions:
17+
contents: read
18+
pull-requests: write
19+
20+
jobs:
21+
summary:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/github-script@v7
25+
with:
26+
script: |
27+
const MARKER = '<!-- awesome-gno-pr-bot -->';
28+
try {
29+
const { owner, repo } = context.repo;
30+
const pr = context.payload.pull_request;
31+
const number = pr.number;
32+
33+
// Head README (data only — no code execution).
34+
let headLines = [];
35+
try {
36+
const { data } = await github.rest.repos.getContent({
37+
owner: pr.head.repo.owner.login,
38+
repo: pr.head.repo.name,
39+
path: 'README.md',
40+
ref: pr.head.sha,
41+
});
42+
headLines = Buffer.from(data.content, 'base64').toString('utf8').split('\n');
43+
} catch (e) { /* README may not exist on head; ignore */ }
44+
45+
// Added / removed list entries from the README diff.
46+
const files = await github.paginate(github.rest.pulls.listFiles, {
47+
owner, repo, pull_number: number, per_page: 100,
48+
});
49+
const readme = files.find(f => f.filename === 'README.md');
50+
const added = [], removed = [];
51+
if (readme && readme.patch) {
52+
for (const line of readme.patch.split('\n')) {
53+
if (/^\+- \[/.test(line)) added.push(line.slice(1));
54+
else if (/^-- \[/.test(line)) removed.push(line.slice(1));
55+
}
56+
}
57+
58+
const nameOf = l => ((l.match(/\[([^\]]+)\]/) || [])[1] || '?');
59+
const urlOf = l => { const m = l.match(/\]\((https?:\/\/[^)\s]+)\)/); return m ? m[1] : null; };
60+
const sectionOf = entry => {
61+
const i = headLines.indexOf(entry);
62+
if (i < 0) return null;
63+
for (let j = i; j >= 0; j--) if (headLines[j].startsWith('## ')) return headLines[j].slice(3).trim();
64+
return null;
65+
};
66+
const check = async u => {
67+
try {
68+
const r = await fetch(u, { redirect: 'follow', headers: { 'User-Agent': 'awesome-gno-pr-bot' } });
69+
return r.status;
70+
} catch (e) { return 0; }
71+
};
72+
73+
let body = `${MARKER}\n### 📋 awesome-gno PR summary\n\n`;
74+
if (added.length === 0 && removed.length === 0) {
75+
body += `_No list entries added or removed in this PR._\n`;
76+
} else {
77+
if (added.length) {
78+
const rows = [];
79+
for (const l of added) {
80+
const u = urlOf(l);
81+
const s = sectionOf(l) || '—';
82+
const st = u ? await check(u) : null;
83+
const ok = st && (st < 400 || st === 403 || st === 429);
84+
const status = st == null ? '—' : (ok ? `✅ ${st}` : `❌ ${st || 'conn'}`);
85+
rows.push(`| ${nameOf(l)} | ${s} | ${u ? `[link](${u})` : '—'} | ${status} |`);
86+
}
87+
body += `**Added ${added.length} ${added.length === 1 ? 'entry' : 'entries'}:**\n\n`;
88+
body += `| Entry | Section | Link | Status |\n|---|---|---|---|\n${rows.join('\n')}\n\n`;
89+
}
90+
if (removed.length) {
91+
body += `**Removed ${removed.length}:**\n${removed.map(l => `- ${nameOf(l)}`).join('\n')}\n\n`;
92+
}
93+
}
94+
body += `<sub>Live link check — 403/429 are shown but tolerated (some hosts block CI runners). `;
95+
body += `The **awesome-lint** and **link-check** jobs are the authoritative gate.</sub>`;
96+
97+
const comments = await github.paginate(github.rest.issues.listComments, {
98+
owner, repo, issue_number: number, per_page: 100,
99+
});
100+
const existing = comments.find(c => c.body && c.body.includes(MARKER));
101+
if (existing) {
102+
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
103+
} else {
104+
await github.rest.issues.createComment({ owner, repo, issue_number: number, body });
105+
}
106+
} catch (err) {
107+
core.warning(`pr-summary bot failed (non-blocking): ${err.message}`);
108+
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ _Apps developed by the gno.land community._
6767
- [Adena Wallet](https://adena.app/) - Friendly wallet that simplifies sending & receiving tokens, staking, NFT storage, and dapp connections.
6868
- [Gnolove](https://gnolove.world) - Community leaderboard and contributions analytics for builders of the Gnoland ecosystem.
6969
- [Zenao](https://zenao.io) - Organize events in seconds then build your resilient community & social organizations.
70+
- [Gnomputer](https://github.com/moul/gnomputer) - A windowed web workstation for browsing realms, source, and live chain activity.
7071

7172
## Tools
7273

@@ -84,6 +85,7 @@ _Tools useful for developing in Gno._
8485
- [gno.nvim](https://github.com/x1unix/gno.nvim) - Gno language support for NeoVim.
8586
- [gnopls](https://github.com/gnoverse/gnopls) - A language server providing editor features like autocompletion, hover, and go-to-definition.
8687
- [gno-mcp](https://github.com/gnoverse/gno-mcp) - An MCP server and agent skill connecting realms to AI coding assistants like Claude, Cursor, and Gemini CLI.
88+
- [gnovanity](https://github.com/gnoverse/gnovanity) - A command-line tool for generating vanity wallet addresses.
8789
- [gno-explorer](https://github.com/gnoverse/gno-explorer) - A dashboard surfacing indexer metrics such as realm, package, and address counts.
8890

8991
## Tutorials, Presentations, Resources
@@ -101,6 +103,7 @@ _Resources to help you understand how to get around gno.land and use Gno._
101103
- [Gno Chinese Station](https://www.gnoland.cn) - A website for Chinese developers, providing tutorials, resources, and Gno news.
102104
- [Failing In Public](https://proggr.hashnode.dev/gnoland-initial-experience-gonzo-take-on-failing-in-public) - A gonzo journalist take on first gno/CosmosSDK experiences.
103105
- ["go -> gno" presentation](https://github.com/gnolang/workshops/tree/main/presentations/2023-06-26--go-to-gno--schollz) - "Things I wish I knew when I started out with Gno, when coming from a Go background" by Zack Scholl.
106+
- [gno-contracts](https://github.com/moul/gno-contracts) - A collection of 50+ versioned, self-contained gno.land packages and realms by moul, tested against gno master.
104107

105108
## SDKs & Clients
106109

@@ -116,6 +119,7 @@ _Connecting web2 to the gno.land blockchain._
116119
_Collections of gno packages providing generic functionality which developers can extend with custom code to create applications._
117120

118121
- [daokit](https://github.com/samouraiworld/gnodaokit) - Create DAOs that can mirror real-world organizations.
122+
- [gnit](https://github.com/gnoverse/gnit) - A composable Git protocol package that lets any realm act as a Git repository.
119123

120124
## Socials
121125

0 commit comments

Comments
 (0)