Skip to content

Commit e71b856

Browse files
refactor: address code review feedback in PR #13
- Fix variable shadowing issue in src/organization.js (renamed `org` to `orgData`) - Update getOrganization to use getGraphqlClient() pattern for consistency - Add parameter validation for getOrganization - Merge main branch changes (locations, users, files features) - Handle permission errors in organization test gracefully - All tests passing (65/65) - ESLint passing with no errors Resolves code review comment from Copilot about variable shadowing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2 parents 7b3d7f0 + 47df775 commit e71b856

27 files changed

+9877
-2264
lines changed

.github/workflows/release.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
8+
jobs:
9+
test:
10+
uses: ./.github/workflows/test.yml
11+
secrets: inherit
12+
13+
release:
14+
needs: [test]
15+
runs-on: ubuntu-latest
16+
permissions:
17+
id-token: write # Required for OIDC/provenance
18+
contents: write # Required for semantic-release to create releases
19+
issues: write # Required for semantic-release to comment on issues
20+
pull-requests: write # Required for semantic-release to comment on PRs
21+
steps:
22+
- uses: actions/checkout@v5
23+
with:
24+
fetch-depth: 0
25+
persist-credentials: false
26+
- uses: actions/setup-node@v6
27+
with:
28+
node-version: 24
29+
cache: 'npm'
30+
registry-url: 'https://registry.npmjs.org'
31+
- run: npm ci
32+
- run: npx semantic-release
33+
env:
34+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
36+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
37+
HUSKY: 0
38+
NPM_CONFIG_PROVENANCE: true

.github/workflows/release.yml.skip

Lines changed: 0 additions & 31 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- '**'
7+
push:
8+
branches:
9+
- '**'
10+
- '!main'
11+
workflow_call:
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
node-version: [20, 22, 24]
19+
steps:
20+
- uses: actions/checkout@v5
21+
- uses: actions/setup-node@v6
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
cache: 'npm'
25+
- run: npm ci
26+
- run: npm run lint
27+
- run: npm test

.github/workflows/test.yml.skip

Lines changed: 0 additions & 25 deletions
This file was deleted.

README.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@
22

33
[![npm version](https://img.shields.io/npm/v/gitevents-fetch.svg)](https://www.npmjs.com/package/gitevents-fetch)
44
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5+
[![npm provenance](https://img.shields.io/badge/provenance-attested-green)](https://docs.npmjs.com/generating-provenance-statements)
56

67
A Node.js library for fetching events and talks from GitEvents-based GitHub repositories using GitHub's GraphQL API. GitEvents uses GitHub Issues as a data source for managing community events and talk submissions.
78

9+
> **Security**: This package is published with [npm provenance](https://docs.npmjs.com/generating-provenance-statements) attestation, ensuring verifiable supply chain security.
10+
811
## Features
912

1013
- 🚀 Fetch upcoming and past events from GitHub Issues
1114
- 🎤 Retrieve event talks and speaker submissions (via sub-issues)
1215
- 🏢 Fetch organization statistics and metadata
16+
- 📍 Fetch and validate location data with consistent schema
17+
- 👤 Fetch user profiles and speaker information
18+
- 📄 Fetch file contents from repositories (text files, JSON, etc.)
1319
- 👥 Fetch GitHub Teams and team members
1420
- 🔐 Support for both GitHub Personal Access Tokens (PAT) and GitHub App authentication
1521
- 📊 Parse structured event data using issue forms
@@ -250,6 +256,190 @@ console.log(org)
250256
// }
251257
```
252258

259+
### `getUser(login)`
260+
261+
Fetch a GitHub user profile (useful for speaker information).
262+
263+
**Parameters:**
264+
265+
- `login` (string) - GitHub username
266+
267+
**Returns:** `Promise<User | null>`
268+
269+
Returns user data or `null` if not found.
270+
271+
**Example:**
272+
273+
```javascript
274+
import { getUser } from 'gitevents-fetch'
275+
276+
const user = await getUser('octocat')
277+
278+
console.log(user)
279+
// {
280+
// login: 'octocat',
281+
// name: 'The Octocat',
282+
// bio: 'GitHub mascot',
283+
// avatarUrl: 'https://github.com/octocat.png',
284+
// url: 'https://github.com/octocat',
285+
// websiteUrl: 'https://octocat.com',
286+
// company: 'GitHub',
287+
// location: 'San Francisco',
288+
// email: 'octocat@github.com',
289+
// createdAt: Date('2011-01-25T18:44:36.000Z'),
290+
// updatedAt: Date('2024-01-01T00:00:00.000Z'),
291+
// followerCount: 1000,
292+
// followingCount: 10,
293+
// publicRepoCount: 8,
294+
// socialAccounts: [
295+
// { provider: 'LINKEDIN', url: 'https://linkedin.com/in/octocat' }
296+
// ]
297+
// }
298+
```
299+
300+
### `getFile(org, repo, filePath, options?)`
301+
302+
Fetch file contents from a repository.
303+
304+
**Parameters:**
305+
306+
- `org` (string) - GitHub organization or user name
307+
- `repo` (string) - Repository name
308+
- `filePath` (string) - Path to the file in the repository
309+
- `options` (object, optional) - Options
310+
- `branch` (string) - Branch name (default: 'HEAD')
311+
- `parse` (boolean) - Auto-parse JSON files (default: false)
312+
313+
**Returns:** `Promise<string | object>`
314+
315+
Returns string content by default, or parsed object if `parse: true` is used with JSON files.
316+
317+
**Example:**
318+
319+
```javascript
320+
import { getFile } from 'gitevents-fetch'
321+
322+
// Fetch text file
323+
const readme = await getFile('myorg', 'myrepo', 'README.md')
324+
console.log(readme) // "# My Project\n..."
325+
326+
// Fetch JSON file with auto-parsing
327+
const data = await getFile('myorg', 'myrepo', 'data.json', { parse: true })
328+
console.log(data) // { key: 'value', ... }
329+
330+
// Fetch from specific branch
331+
const config = await getFile('myorg', 'myrepo', 'config.json', {
332+
branch: 'develop',
333+
parse: true
334+
})
335+
```
336+
337+
**Error Handling:**
338+
339+
- Throws `File not found` error if file doesn't exist
340+
- Throws `Binary files are not supported` error for binary files
341+
- Throws `Failed to parse JSON` error if parse: true but content is invalid JSON
342+
343+
### `getLocations(org, repo, options?)`
344+
345+
Fetch and validate location data from a repository with consistent schema.
346+
347+
**Parameters:**
348+
349+
- `org` (string) - GitHub organization or user name
350+
- `repo` (string) - Repository name
351+
- `options` (object, optional) - Options
352+
- `fileName` (string) - File name (default: 'locations.json')
353+
- `branch` (string) - Branch name (default: 'HEAD')
354+
355+
**Returns:** `Promise<{ locations: Location[], errors: Error[] | null }>`
356+
357+
Returns validated locations and any validation errors.
358+
359+
**Example:**
360+
361+
```javascript
362+
import { getLocations } from 'gitevents-fetch'
363+
364+
const result = await getLocations('myorg', 'events')
365+
366+
console.log(result.locations)
367+
// [
368+
// {
369+
// id: 'venue-1',
370+
// name: 'Tech Hub',
371+
// address: '123 Main St, City',
372+
// coordinates: { lat: 40.7128, lng: -74.006 },
373+
// url: 'https://techhub.com',
374+
// what3words: 'filled.count.soap',
375+
// description: 'A modern tech venue',
376+
// capacity: 100,
377+
// accessibility: 'Wheelchair accessible'
378+
// }
379+
// ]
380+
381+
// Check for validation errors
382+
if (result.errors) {
383+
console.log('Invalid locations:', result.errors)
384+
}
385+
386+
// Use custom file name
387+
const venues = await getLocations('myorg', 'events', {
388+
fileName: 'venues.json'
389+
})
390+
```
391+
392+
**Location Schema:**
393+
394+
Required fields:
395+
396+
- `id` (string) - Unique identifier
397+
- `name` (string) - Location name
398+
399+
Optional fields (null if not provided):
400+
401+
- `address` (string) - Physical address
402+
- `coordinates` (object) - { lat: number, lng: number }
403+
- `url` (string) - Location website
404+
- `what3words` (string) - what3words address
405+
- `description` (string) - Location description
406+
- `capacity` (number) - Venue capacity
407+
- `accessibility` (string) - Accessibility information
408+
- Custom fields are preserved
409+
410+
**Validation:**
411+
412+
The function validates each location and returns:
413+
414+
- `locations` - Array of valid, normalized locations
415+
- `errors` - Array of validation errors (null if all valid)
416+
417+
Each error includes:
418+
419+
- `index` - Array index of invalid location
420+
- `id` - Location ID (if available)
421+
- `errors` - Array of validation error messages
422+
423+
### Fetching Talks from a Dedicated Repository
424+
425+
Talks stored as issues in a dedicated repository can be fetched using the existing event functions:
426+
427+
```javascript
428+
import { upcomingEvents, event } from 'gitevents-fetch'
429+
430+
// Fetch all talks (using different label if needed)
431+
const talks = await upcomingEvents('myorg', 'talks-repo')
432+
433+
// Fetch specific talk by issue number
434+
const talk = await event('myorg', 'talks-repo', 42)
435+
```
436+
437+
Configure a custom label in your environment if talks use a different label:
438+
439+
```bash
440+
export DEFAULT_APPROVED_EVENT_LABEL="Approved Talk"
441+
```
442+
253443
### Event Object Structure
254444

255445
```typescript

0 commit comments

Comments
 (0)