Skip to content
Merged
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
13 changes: 12 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Contributing

- [Communication](#communication)
- [Setting up a Development Environment](#setting-up-your-development-environment)
- [GitHub workflow](#github-workflow)
- [Open a Pull Request](#opening-a-pull-request)
- [Code Review](#code-review)
Expand All @@ -17,11 +18,21 @@ Please do not ever hesitate to ask a question or send a pull request.

Beginner focused information can be found below in [Open a Pull Request](#opening-a-pull-request) and [Code Review](#code-review).

### Communication
## Communication

Reporting issues? Our unified issue queue is a good place for this: https://github.com/haxtheweb/issues/issues
Need to discuss something via chat? Our [Discord can be joined here](https://bit.ly/hax-discord).

## Setting up a Development Environment
HAX has a built-in module for onboarding `hax party`! It'll get you up and running with tooling, repositories, and the community.

### System dependencies
* [git](https://git-scm.com/)
* [gh](https://cli.github.com/) (optional)
* [yarn](https://yarnpkg.com/)

`hax party` works great with just `git`, but contributors can get some extra convenience with GitHub's own `gh` utility. (You can fork repos directly from the CLI, rather than visiting the browser every time!)

## GitHub workflow

We work primarily using pull requests and forks. In order to work most effectively, we ask that you FORK any project you are wanting to contribute to in our ecosystem. After taking a fork, submit a pull request while pointing to the associated issue tied to this pull request.
Expand Down
1 change: 1 addition & 0 deletions src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ async function main() {
auditCommandDetected(commandRun, customPath)
}
else if (commandRun.command === 'party') {
commandRun.options.author = author;
await partyCommandDetected(commandRun);
}
// CLI works within context of the site if one is detected, otherwise we can do other things
Expand Down
139 changes: 95 additions & 44 deletions src/lib/programs/party.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@ import * as p from '@clack/prompts';
import color from 'picocolors';
import { merlinSays } from "../statements.js";

const osPathCmd = process.platform === "win32" ? "where.exe" : "which";

let sysGit = true;
exec('which git', error => {
exec(`${osPathCmd} git`, error => {
if (error) {
sysGit = false;
}
});

let sysGh = true;
exec(`${osPathCmd} gh`, error => {
if (error) {
sysGh = false;
}
});

let sysSSH = true;

export function partyActions(){
Expand Down Expand Up @@ -56,7 +65,8 @@ export async function partyCommandDetected(commandRun) {
command: null,
arguments: {},
options: {
// npmClient: `${operation.npmClient}`
npmClient: `${operation.npmClient}`,
author: `${operation.author}`
}
}
operation = await p.group(
Expand Down Expand Up @@ -207,27 +217,41 @@ export async function partyCommandDetected(commandRun) {

async function cloneHAXRepositories(commandRun) {
let s = p.spinner();

// check for system dependencies: ssh, yarn, etc.
if(!sysGit) {
console.error(`${color.red(`Git is not installed. The Git CLI is required to access GitHub with ${color.bold('hax party')}.`)}
Please follow the instructions at:
${color.underline(color.cyan(`https://git-scm.com/book/en/v2/Getting-Started-Installing-Git`))}`);
process.exit(1);
}
await interactiveExec('ssh -T git@github.com', (error, stdout, stderr) => {
const output = stdout + stderr;
// The GitHub SSH test always returns as stderr
if (!output.includes('successfully authenticated')) {
sysSSH = false;

if(!sysGh){
try {
const { stdout, stderr } = await exec('ssh -T git@github.com');
} catch(error) {
// The GitHub SSH test always returns as stderr
if (!error.stderr.includes('successfully authenticated')) {
sysSSH = false;
}
}
});

if(!sysSSH) {
console.error(`${color.red(`SSH keys are not set up correctly. SSH is required to access GitHub with ${color.bold('hax party')}.`)}
Please follow the instructions at:
${color.underline(color.cyan(`https://docs.github.com/en/authentication/connecting-to-github-with-ssh`))}`);
process.exit(1);
if(!sysSSH) {
console.error(`${color.red(`SSH keys are not set up correctly. SSH is required to access GitHub with ${color.bold('hax party')}.`)}
Please follow the instructions at:
${color.underline(color.cyan(`https://docs.github.com/en/authentication/connecting-to-github-with-ssh`))}`);
process.exit(1);
}
} else {
// gh cli can make new ssh keys and push them to GitHub
try {
await exec('gh auth status')
} catch {
console.log(`${color.red(`You have GitHub CLI installed, but it is not properly authenticated.`)}
To access GitHub with ${color.bold('hax party')}, please follow this guided login:
Select the ${color.cyan(`Generate a new SSH key`)} and ${color.cyan(`Login with a web browser`)} options`);

await interactiveExec('gh', ['auth', 'login', '-p', 'ssh', '--clipboard'])
}
}

try {
Expand All @@ -237,22 +261,13 @@ async function cloneHAXRepositories(commandRun) {
}

for (const item of commandRun.options.repos) {
// while loop keeps HAX active until the user is ready
let isForked = false;
let firstRun = true;
while(!isForked) {
// If GitHub CLI is installed
if(sysGh){
try {
// ssh link is used since https prompts for password
if(firstRun){
s.start(`Cloning ${color.bold(item)} to ${color.bold(process.cwd())}`);
} else {
s.start(`Trying again... Cloning ${item} to ${color.bold(process.cwd())}`);
}

s.start(`Cloning ${color.bold(item)} to ${color.bold(process.cwd())}`);
await exec(`git clone git@github.com:${commandRun.options.author}/${item}.git`);
s.stop(`${color.green("Successfully")} cloned ${color.bold(item)} to ${color.bold(process.cwd())}`);

isForked = true;
} catch (e) {
// skip the loop if the repo already exists
if(e.stderr.includes("already exists and is not an empty directory")){
Expand All @@ -262,27 +277,63 @@ async function cloneHAXRepositories(commandRun) {

s.stop(`${color.red("Failed")} to clone ${color.bold(item)} to ${color.bold(process.cwd())}`);

p.note(`${color.red(`Error: HAX cannot find a personal ${color.bold("fork")} of the ${color.bold(item)} repository on your GitHub account`)}
Use the following link to fork ${color.bold(item)}: ${color.underline(color.cyan(`https://github.com/haxtheweb/${item}/fork`))}`);
p.note(`${color.red(`Error: HAX could not find your personal ${color.bold("fork")} of the ${color.bold(item)} repository on GitHub`)}`)

s.start(`Using ${color.bold(`gh repo`)} utility to fork and clone ${color.bold(item)}`);
await exec(`gh repo fork haxtheweb/${item} --clone`)
s.stop(`${color.green("Successfully")} cloned ${color.bold(item)} to ${color.bold(process.cwd())}`);
}
}
// Standard git, not GitHub CLI
else {
// while loop keeps HAX active until the user is ready
let isForked = false;
let firstRun = true;

while(!isForked) {
try {
// ssh link is used since https prompts for password
if(firstRun){
s.start(`Cloning ${color.bold(item)} to ${color.bold(process.cwd())}`);
} else {
s.start(`Trying again... Cloning ${item} to ${color.bold(process.cwd())}`);
}

// We don't want to spam the link every time
if(firstRun){
p.intro(`${merlinSays("The link will open in your browser in a few seconds")}`)
setTimeout(async () => {
await open(`https://github.com/haxtheweb/${item}/fork`)
}, 3000);
firstRun = false;
}
await exec(`git clone git@github.com:${commandRun.options.author}/${item}.git`);
s.stop(`${color.green("Successfully")} cloned ${color.bold(item)} to ${color.bold(process.cwd())}`);

let response = await p.confirm({
message: `Have you forked the repository? Would you like to try again?`,
initialValue: true,
});
isForked = true;
} catch (e) {
// skip the loop if the repo already exists
if(e.stderr.includes("already exists and is not an empty directory")){
s.stop(`${color.yellow(`${color.bold(`${item}`)} already exists in ${color.bold(process.cwd())}`)}`);
break;
}

// Multiple ways to quit (select no, ctrl+c, etc)
if(p.isCancel(response) || !response) {
p.cancel('🧙 Merlin: Canceling CLI.. HAX ya later 🪄');
process.exit(0);
s.stop(`${color.red("Failed")} to clone ${color.bold(item)} to ${color.bold(process.cwd())}`);

p.note(`${color.red(`Error: HAX cannot find a personal ${color.bold("fork")} of the ${color.bold(item)} repository on your GitHub account`)}
Use the following link to fork ${color.bold(item)}: ${color.underline(color.cyan(`https://github.com/haxtheweb/${item}/fork`))}`);

// We don't want to spam the link every time
if(firstRun){
p.intro(`${merlinSays("The link will open in your browser in a few seconds")}`)
setTimeout(async () => {
await open(`https://github.com/haxtheweb/${item}/fork`)
}, 3000);
firstRun = false;
}

let response = await p.confirm({
message: `Have you forked the repository? Would you like to try again?`,
initialValue: true,
});

// Multiple ways to quit (select no, ctrl+c, etc)
if(p.isCancel(response) || !response) {
p.cancel('🧙 Merlin: Canceling CLI.. HAX ya later 🪄');
process.exit(0);
}
}
}
}
Expand Down
Loading