Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d7134ad
Showing
15 changed files
with
434 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
name: Setup Project | ||
description: Prepare the project in GitHub Actions | ||
|
||
inputs: | ||
bun-version: | ||
description: Version of Bun to use | ||
default: latest | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
- name: 🏗 Setup Node | ||
uses: oven-sh/setup-bun@v1 | ||
with: | ||
bun-version: ${{ inputs.bun-version }} | ||
|
||
- name: 📦 Install dependencies | ||
run: bun install | ||
shell: bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: review | ||
|
||
on: | ||
workflow_dispatch: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
types: [opened, synchronize] | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
packages: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: 🏗 Setup repository | ||
uses: actions/checkout@v3 | ||
|
||
- name: 🏗 Setup project | ||
uses: ./.github/actions/setup-project | ||
|
||
# - name: ✅ Lint packages | ||
# run: bun run lint --max-warnings 0 | ||
|
||
- name: 👷 Build packages | ||
run: bun run build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files | ||
|
||
# project | ||
build/ | ||
|
||
# dependencies | ||
node_modules/ | ||
npm-debug.* | ||
yarn-debug.* | ||
yarn-error.* | ||
package-lock.json | ||
yarn.lock | ||
|
||
# macOS | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# tutorial | ||
|
||
Quick access to Expo and React Native tutorials from your terminal. | ||
|
||
``` | ||
npx tutorial | ||
``` | ||
|
||
<hr /> | ||
|
||
Thank you [Gabe](https://github.com/garbles) for the package name! |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "tutorial", | ||
"version": "0.1.4", | ||
"description": "Open a tutorial for Expo, EAS, React, and React Native", | ||
"keywords": [ | ||
"tutorial", | ||
"react-native", | ||
"cli" | ||
], | ||
"type": "module", | ||
"main": "build/index.js", | ||
"bin": "build/index.js", | ||
"file": [ | ||
"build" | ||
], | ||
"scripts": { | ||
"start": "bun build ./src/index.ts --outdir ./build --target node", | ||
"build": "bun build ./src/index.ts --outdir ./build --target node --minify", | ||
"clean": "git clean ./build -xdf", | ||
"lint": "eslint ." | ||
}, | ||
"author": "Brent Vatne <brent@expo.dev>, Cedric van Putten <github@cedric.dev>", | ||
"license": "MIT", | ||
"files": [ | ||
"build" | ||
], | ||
"devDependencies": { | ||
"@types/getenv": "^1.0.3", | ||
"@types/js-yaml": "^4.0.9", | ||
"arg": "^5.0.2", | ||
"chalk": "^5.3.0", | ||
"eslint": "^8.56.0", | ||
"eslint-config-universe": "^12.0.0", | ||
"getenv": "^1.0.0", | ||
"js-yaml": "^4.1.0", | ||
"open": "^10.0.3", | ||
"ora": "^8.0.1", | ||
"prettier": "^3.2.4", | ||
"prompts": "^2.4.2" | ||
}, | ||
"eslintConfig": { | ||
"extends": "universe/node" | ||
}, | ||
"prettier": { | ||
"printWidth": 100, | ||
"tabWidth": 2, | ||
"singleQuote": true, | ||
"bracketSameLine": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#!/usr/bin/env node | ||
import arg from 'arg'; | ||
|
||
import { pickTutorial } from './pickTutorial'; | ||
import { renderHelp } from './renderHelp'; | ||
import { handleError } from './utils/errors'; | ||
|
||
export type Input = typeof args; | ||
|
||
const args = arg({ | ||
'--help': Boolean, | ||
'--version': Boolean, | ||
'-h': '--help', | ||
'-v': '--version', | ||
}); | ||
|
||
if (args['--help']) { | ||
console.log(renderHelp()); | ||
process.exit(0); | ||
} | ||
|
||
if (args['--version']) { | ||
console.log(require('../package.json').version); | ||
process.exit(0); | ||
} | ||
|
||
process.on('SIGINT', () => process.exit(0)); | ||
process.on('SIGTERM', () => process.exit(0)); | ||
|
||
await pickTutorial(args).catch(handleError); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import chalk from 'chalk'; | ||
import open from 'open'; | ||
import ora from 'ora'; | ||
|
||
import { type Input } from '.'; | ||
import { prompt } from './utils/prompts'; | ||
|
||
type Choice = { | ||
id: string; | ||
title: string; | ||
description: string; | ||
value: { | ||
url: string; | ||
title: string; | ||
}; | ||
}; | ||
|
||
const choices: Choice[] = [ | ||
{ | ||
id: '_blank', | ||
title: 'The fundamentals of developing an app with Expo', | ||
description: `A guided tutorial that walks you through the basics of creating a universal app that runs on Android, iOS and the web`, | ||
value: { | ||
url: 'https://docs.expo.dev/tutorial/', | ||
title: '_blank', | ||
}, | ||
}, | ||
{ | ||
id: '_blank', | ||
title: 'Build and deploy your app with Expo Application Services (EAS)', | ||
description: `Everything you need to know to get started with EAS and build and deploy your app to the app stores`, | ||
value: { | ||
url: 'https://egghead.io/courses/build-and-deploy-react-native-apps-with-expo-eas-85ab521e', | ||
title: '_blank', | ||
}, | ||
}, | ||
{ | ||
id: '_blank', | ||
title: 'Introduction to React Native', | ||
description: `Learn about the React fundamentals and basic APIs and components that you'll need for any React Native app`, | ||
value: { | ||
url: 'https://reactnative.dev/docs/getting-started', | ||
title: '_blank', | ||
}, | ||
}, | ||
]; | ||
|
||
export async function pickTutorial(arg: Input) { | ||
if (!process.stdout.isTTY) { | ||
await open(choices[0].value.url); | ||
} | ||
|
||
const { choice } = await prompt({ | ||
type: 'select', | ||
name: 'choice', | ||
message: 'Pick a tutorial', | ||
choices, | ||
}); | ||
|
||
await open(choice.url); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import chalk from 'chalk'; | ||
|
||
import { detectPackageManager } from './utils/node'; | ||
|
||
export function renderHelp() { | ||
const manager = detectPackageManager(); | ||
|
||
// Note, template literal is broken with bun build | ||
// In the future, support: | ||
// ${chalk.dim('$')} ${manager} [tool] | ||
return ` | ||
${chalk.bold('Usage')} | ||
${chalk.dim('$')} ${manager} [tool] | ||
${chalk.bold('Options')} | ||
--version, -v Version number | ||
--help, -h Usage info | ||
`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { boolish } from 'getenv'; | ||
|
||
export const env = { | ||
get CI() { | ||
return boolish('CI', false); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import chalk from 'chalk'; | ||
|
||
export class AbortError extends Error { | ||
readonly name = 'AbortError'; | ||
} | ||
|
||
export class CommandError extends Error { | ||
readonly name = 'CommandError'; | ||
|
||
constructor( | ||
readonly code: string, | ||
message: string = '', | ||
) { | ||
super(message); | ||
} | ||
} | ||
|
||
export function handleError(error: any) { | ||
switch (error?.name) { | ||
case 'AbortError': | ||
console.warn(chalk.red(`Command aborted: ${error.message}`)); | ||
return process.exit(1); | ||
|
||
case 'CommandError': | ||
console.warn(chalk.red(`Command failed: ${error.message} (${error.code})`)); | ||
return process.exit(1); | ||
|
||
default: | ||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import yaml from 'js-yaml'; | ||
import { Octokit } from 'octokit'; | ||
|
||
export type GithubRepository = { | ||
owner: string; | ||
name: string; | ||
}; | ||
|
||
type GithubIssueTemplate = { | ||
id: string; | ||
name: string; | ||
description?: string; | ||
labels?: string[]; | ||
projects?: string[]; | ||
assignees?: string[]; | ||
body?: any; | ||
}; | ||
|
||
/** @see https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content */ | ||
async function fetchIssueTemplateFileNames(github: Octokit, repo: GithubRepository) { | ||
let response: Awaited<ReturnType<typeof github.rest.repos.getContent>>; | ||
|
||
try { | ||
response = await github.rest.repos.getContent({ | ||
owner: repo.owner, | ||
repo: repo.name, | ||
path: '.github/ISSUE_TEMPLATE', | ||
mediaType: { | ||
format: 'raw', | ||
}, | ||
}); | ||
} catch (error) { | ||
if (error.status === 404) return []; | ||
throw error; | ||
} | ||
|
||
// TODO: figure out why this is a thing | ||
if (!Array.isArray(response.data)) return []; | ||
|
||
return response.data | ||
.filter( | ||
(entity) => | ||
entity.type === 'file' && (entity.path.endsWith('.yml') || entity.path.endsWith('.yaml')), | ||
) | ||
.map((file) => ({ | ||
name: file.name as string, | ||
path: file.path as string, | ||
sha: file.sha as string, | ||
size: file.size as number, | ||
downloadUrl: file.download_url as string, | ||
})); | ||
} | ||
|
||
/** | ||
* Fetch the issue template, and configuration, from a GitHub repository. | ||
* This checks the `.github/ISSUE_TEMPLATE` directory for files ending in `.yml` or `.yaml`. | ||
* | ||
* @see https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser | ||
*/ | ||
export async function fetchIssueTemplates(github: Octokit, repo: GithubRepository) { | ||
const files = await fetchIssueTemplateFileNames(github, repo); | ||
const contents = await Promise.allSettled( | ||
files.map((file) => | ||
fetch(file.downloadUrl) | ||
.then((response) => response.text()) | ||
.then((content) => yaml.load(content) as any), | ||
), | ||
); | ||
|
||
const filesWithContent = contents.map((content, index) => ({ | ||
...files[index], | ||
content: content.status === 'fulfilled' ? content.value : undefined, | ||
})); | ||
|
||
const configFile = filesWithContent.find( | ||
(file) => file.name === 'config.yml' || file.name === 'config.yaml', | ||
); | ||
|
||
return { | ||
emptyIssuesEnabled: configFile?.content?.blank_issues_enabled ?? true, | ||
links: configFile?.content?.contact_links ?? [], | ||
templates: filesWithContent.filter((file) => file !== configFile), | ||
}; | ||
} | ||
|
||
/** | ||
* Create the URL used to fill in a new issue, using optional template. | ||
* | ||
* @see https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms | ||
*/ | ||
export function createGithubIssueUrl(repo: GithubRepository, template?: GithubIssueTemplate) { | ||
const url = new URL(`https://github.com/${repo.owner}/${repo.name}/issues/new`); | ||
|
||
if (!template) return `${url}`; | ||
|
||
url.searchParams.append('template', template.id); | ||
|
||
if (template.labels?.length) { | ||
url.searchParams.append('labels', template.labels.join(',')); | ||
} | ||
|
||
if (template.projects?.length) { | ||
url.searchParams.append('projects', template.projects.join(',')); | ||
} | ||
|
||
if (template.assignees?.length) { | ||
url.searchParams.append('assignees', template.assignees.join(',')); | ||
} | ||
|
||
return `${url}`; | ||
} |
Oops, something went wrong.