Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Create pull request #1376

Merged
merged 73 commits into from Apr 12, 2018
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
2aa2d11
Begin a test for the PrSelectionByBranch component
smashwilson Apr 3, 2018
6fa3d48
Turns out we need more props than that
smashwilson Apr 3, 2018
bf0501f
Tests for an unpublished branch
smashwilson Apr 3, 2018
58acc56
Render "create pull request" controls
smashwilson Apr 3, 2018
daffe22
Wire up the "search again" link
smashwilson Apr 3, 2018
7bdd34e
Handle published branches with unpushed commits
smashwilson Apr 3, 2018
f02b163
Finally, published branches that are up to date
smashwilson Apr 3, 2018
21a1f20
Unused @autobinds
smashwilson Apr 4, 2018
c9e3e15
Push to a manually specified Remote
smashwilson Apr 4, 2018
9d7d532
Pass props through the PrInfoController
smashwilson Apr 4, 2018
781d0ea
Pass props through RemotePrController
smashwilson Apr 4, 2018
9ff87da
Implement create PR handler in RemotePrController
smashwilson Apr 4, 2018
3dc74d8
aheadCount is null on branches without a remote tracking branch
smashwilson Apr 4, 2018
c1fbe3d
Collect aheadCount and isUnpublished from the repository
smashwilson Apr 4, 2018
0321d5d
Branch pushing action in the GithubTabController
smashwilson Apr 4, 2018
33d6421
Refactor and style New PR
simurai Apr 5, 2018
e29783d
Add space after link
simurai Apr 5, 2018
dadfc86
Consolidate into a single button
smashwilson Apr 5, 2018
6131c21
Roll onPushBranch into onCreatePr
smashwilson Apr 5, 2018
a840f2a
Disable the button while a push is in progress
smashwilson Apr 5, 2018
cf3f134
Collect and propagate pushInProgress through components
smashwilson Apr 5, 2018
e0ee176
Show a special message on the repository's main branch
smashwilson Apr 5, 2018
6b16dbf
Recompile Relay queries to fetch defaultBranchName
smashwilson Apr 5, 2018
68ceccc
options parameter is... optional
smashwilson Apr 5, 2018
367e1b4
:art: whitespace
smashwilson Apr 5, 2018
694c837
Pass current and upstream Branch props as model objects
smashwilson Apr 6, 2018
3bb1b03
Adjust PrSelectionByBranchContainer tests to use Real Model Objects :tm:
smashwilson Apr 6, 2018
0f0eb7f
isUnpublished prop is redundant now
smashwilson Apr 6, 2018
009f8d8
Retrieve more information from for-each-ref
smashwilson Apr 6, 2018
9340685
Model remote tracking branches
smashwilson Apr 6, 2018
6b96a51
Construct Branch models with more information about tracking refs
smashwilson Apr 6, 2018
8fb40f6
Move getCurrentBranch into Repository
smashwilson Apr 6, 2018
1bf8f9a
Add .getRefSha() backed by git show-ref
smashwilson Apr 6, 2018
5e669a2
Cached .getRefSha() Repository method
smashwilson Apr 6, 2018
db21ca4
Pass Branches as model objects
smashwilson Apr 6, 2018
c23771a
Remove unused import
smashwilson Apr 6, 2018
9e346a9
Construct Branches with `head` parameter
smashwilson Apr 6, 2018
d8c38ce
Track the head SHA of each branch as well
smashwilson Apr 10, 2018
5908277
Model an indexed collection of Branches as a BranchSet
smashwilson Apr 10, 2018
ea31ecf
Return a BranchSet from Repository.getBranches()
smashwilson Apr 10, 2018
ac133c7
Accessor for Branch names
smashwilson Apr 10, 2018
b8b82d0
Expect BranchSets from the other call sites of .getBranches()
smashwilson Apr 10, 2018
a29b5ef
Index BranchSet branches by fetch and push remote name as well as ref
smashwilson Apr 10, 2018
8c042a4
Query the BranchSet for our upstream status
smashwilson Apr 10, 2018
58a307f
Return Symbols from non-applicable Branch getters
smashwilson Apr 10, 2018
ad778ce
Configure Branch fixture on main
smashwilson Apr 10, 2018
f75dccc
Custom message when HEAD matches the repository's default
smashwilson Apr 10, 2018
2ba332e
Null objects :notes:
smashwilson Apr 10, 2018
f2c493e
Render a message for a detached HEAD
smashwilson Apr 10, 2018
c520d39
Configure BranchSet with a feature branch without an upstream
smashwilson Apr 10, 2018
4410acb
Unit test for a detached HEAD message
smashwilson Apr 10, 2018
f775cc1
Unit test for a branch configured to push elsewhere
smashwilson Apr 10, 2018
f6a4cb9
Detect when the current branch has been pushed to a different remote
smashwilson Apr 10, 2018
b279f83
Missed a call to branches.map()
smashwilson Apr 10, 2018
caad5f9
:art: whitespace around `<strong>`
smashwilson Apr 10, 2018
f6b72b8
Pass the right props and proptypes
smashwilson Apr 10, 2018
de634d5
Patch up GitShellOutStrategy tests
smashwilson Apr 10, 2018
eea4cf9
Detached Branches are always the HEAD
smashwilson Apr 10, 2018
90dd4ca
Use the .isDetached() method
smashwilson Apr 10, 2018
17335d6
Missed a space
smashwilson Apr 10, 2018
fde667d
Show the new remote you're going to publish the branch
smashwilson Apr 10, 2018
47fcc14
Merge branch 'master' of github.com:atom/github into aw/create-pr
smashwilson Apr 10, 2018
dc27e70
Turns out you should update the tests when the code is changed. Who knew
smashwilson Apr 10, 2018
00e998e
:fire: unused getRefSha operation
smashwilson Apr 11, 2018
36ef5de
GraphQL returns a prefix and name for refs
smashwilson Apr 11, 2018
23627c4
prefix includes the /
smashwilson Apr 11, 2018
aa8818d
Don't die horribly when there is no defaultRef
smashwilson Apr 11, 2018
a2a8a59
Don't die horribly when the repository doesn't exist
smashwilson Apr 11, 2018
c808848
Merge branch 'master' into aw/create-pr
smashwilson Apr 11, 2018
2737f67
nullBranch needs getSha() and isHead() methods
smashwilson Apr 12, 2018
fad8915
¯\_(ツ)_/¯
smashwilson Apr 12, 2018
b01c967
Return '' instead of unique Symbols
smashwilson Apr 12, 2018
bb9f4f0
Merge branch 'master' into aw/create-pr
smashwilson Apr 12, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

193 changes: 173 additions & 20 deletions lib/containers/pr-selection-by-branch-container.js
Expand Up @@ -6,21 +6,40 @@ import {autobind} from 'core-decorators';
import PrInfoContainer from './pr-info-container';
import PrUrlInputBox from '../views/pr-url-input-box';
import Octicon from '../views/octicon';
import {RemotePropType, BranchSetPropType} from '../prop-types';

export class PrSelectionByBranch extends React.Component {
static propTypes = {
repository: PropTypes.shape({
defaultBranchRef: PropTypes.shape({
prefix: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}),
pullRequests: PropTypes.shape({
totalCount: PropTypes.number,
totalCount: PropTypes.number.isRequired,
edges: PropTypes.arrayOf(PropTypes.shape({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yay, thank you for using PropTypes.shape!

node: PropTypes.shape({
id: PropTypes.string.isRequired,
number: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
}).isRequired,
})).isRequired,
}),
}),
onSelectPr: PropTypes.func.isRequired,
onUnpinPr: PropTypes.func.isRequired,
onCreatePr: PropTypes.func.isRequired,
onSearchAgain: PropTypes.func.isRequired,
variables: PropTypes.shape({
repoOwner: PropTypes.string.isRequired,
repoName: PropTypes.string.isRequired,
branchName: PropTypes.string.isRequired,
}),
remote: RemotePropType,
aheadCount: PropTypes.number,
branches: BranchSetPropType.isRequired,
pushInProgress: PropTypes.bool.isRequired,
}

constructor(props, context) {
Expand All @@ -40,20 +59,7 @@ export class PrSelectionByBranch extends React.Component {
const repo = this.props.repository;
const {variables} = this.props;
if (!repo || !repo.pullRequests.edges.length) {
return (
<div className="github-PrUrlInputBox-Container">
<PrUrlInputBox onSubmit={this.props.onSelectPr}>
<p className="icon icon-git-pull-request" />
<p>
No pull request could be found for the branch <span className="highlight">{variables.branchName}</span>
on the repository <span className="highlight">{variables.repoOwner}/{variables.repoName}</span>.
</p>
<p>
You can manually pin a GitHub pull request to the current branch by entering its URL:
</p>
</PrUrlInputBox>
</div>
);
return this.renderCreatePr();
}

const edges = repo.pullRequests.edges;
Expand Down Expand Up @@ -89,9 +95,110 @@ export class PrSelectionByBranch extends React.Component {
return this.renderPrSelectionList(edges, repo.pullRequests.totalCount);
}

@autobind
toggleInputBoxVisibility() {
this.setState({displayInputBox: !this.state.displayInputBox});
renderCreatePr() {
return (
<div className="github-PrSelectionByBranch-container">
<div className="github-PrSelectionByBranch-cell">
<div className="github-CreatePr">
<Octicon className="github-CreatePr-icon" icon="git-pull-request" />
<h1 className="github-CreatePr-title">New Pull Request</h1>
{this.renderCreatePrControl()}
</div>
</div>
<hr className="github-PrSelectionByBranch-divider" />
<div className="github-PrSelectionByBranch-cell">
<PrUrlInputBox onSubmit={this.props.onSelectPr}>
<p>
<a className="github-PrSelectionByBranch-searchAgain" onClick={this.props.onSearchAgain}>Search again </a>
to discover an existing pull request, or manually link a GitHub pull request to the current branch by
entering its URL:
</p>
</PrUrlInputBox>
</div>
</div>
);
}

renderCreatePrControl() {
if (!this.props.repository) {
return (
<div className="github-PrSelectionByBranch-message">
<strong>Repository not found</strong> for the remote <code>{this.props.remote.getName()}</code>.
Do you need to update your remote URL?
</div>
);
}

if (this.isDetachedHead()) {
return (
<div className="github-PrSelectionByBranch-message">
You are not currently on any branch.
&nbsp;<strong>Create a new branch</strong>&nbsp;
to share your work with a pull request.
</div>
);
}

if (!this.props.repository.defaultBranchRef) {
return (
<div className="github-PrSelectionByBranch-message">
The repository at remote <code>{this.props.remote.getName()}</code> is
empty. Push a main branch to begin sharing your work.
</div>
);
}

if (this.isOnDefaultRef()) {
return (
<div className="github-PrSelectionByBranch-message">
You are currently on your repository's default branch.
&nbsp;<strong>Create a new branch</strong>&nbsp;
to share your work with a pull request.
</div>
);
}

if (this.isSameAsDefaultRef()) {
return (
<div className="github-PrSelectionByBranch-message">
Your current branch has not moved from the repository's default branch.
&nbsp;<strong>Make some commits</strong>&nbsp;
to share your work with a pull request.
</div>
);
}

let message = 'Open new pull request';
let disable = false;
const differentRemote = this.pushesToDifferentRemote();
if (this.props.pushInProgress) {
message = 'Pushing...';
disable = true;
} else if (!this.hasUpstreamBranch() || differentRemote) {
message = 'Publish + open new pull request';
} else if (this.props.aheadCount > 0) {
message = 'Push + open new pull request';
}

return (
<div>
{differentRemote &&
<div className="github-PrSelectionByBranch-message">
Your current branch is configured to push to the remote
<code>{this.props.branches.getHeadBranch().getPush().getRemoteName()}</code>.
Publish it to <code>{this.props.remote.getName()}</code> instead?
</div>
}
<p className="github-CreatePr-controls">
<button
className="github-PrSelectionByBranch-createPr btn btn-primary"
onClick={this.props.onCreatePr}
disabled={disable}>
{message}
</button>
</p>
</div>
);
}

renderPrSelectionList(edges, totalCount) {
Expand All @@ -109,21 +216,26 @@ export class PrSelectionByBranch extends React.Component {
<PrUrlInputBox onSubmit={this.props.onSelectPr} />
</div>
<ul className="github-PrSelectionByBranch-list">
{edges.map(this.displayPullRequestItem)}
{edges.map(this.renderPrItem)}
</ul>
</div>
);
}

@autobind
displayPullRequestItem({node}) {
renderPrItem({node}) {
return (
<li key={node.id} onClick={e => this.selectPullRequest(e, node)}>
#{node.number}: {node.title}
</li>
);
}

@autobind
toggleInputBoxVisibility() {
this.setState({displayInputBox: !this.state.displayInputBox});
}

@autobind
setPr(prLink) {
this.props.onSelectPr(prLink);
Expand All @@ -134,11 +246,52 @@ export class PrSelectionByBranch extends React.Component {
event.preventDefault();
this.setPr(node.url);
}

getDefaultBranchRef() {
const ref = this.props.repository.defaultBranchRef;
return `${ref.prefix}${ref.name}`;
}

isDetachedHead() {
return !this.props.branches.getHeadBranch().isPresent();
}

isOnDefaultRef() {
if (!this.props.repository) { return false; }

const currentBranch = this.props.branches.getHeadBranch();
return currentBranch.getPush().getRemoteRef() === this.getDefaultBranchRef();
}

isSameAsDefaultRef() {
if (!this.props.repository) { return false; }

const currentBranch = this.props.branches.getHeadBranch();
const mainBranches = this.props.branches.getPushSources(this.props.remote.getName(), this.getDefaultBranchRef());
return mainBranches.some(branch => branch.getSha() === currentBranch.getSha());
}

pushesToDifferentRemote() {
const p = this.props.branches.getHeadBranch().getPush();
if (!p.isRemoteTracking()) { return false; }

const pushRemoteName = p.getRemoteName();
return pushRemoteName !== this.props.remote.getName();
}

hasUpstreamBranch() {
return this.props.branches.getHeadBranch().getUpstream().isPresent();
}
}

export default createFragmentContainer(PrSelectionByBranch, {
repository: graphql`
fragment prSelectionByBranchContainer_repository on Repository {
defaultBranchRef {
prefix
name
}

pullRequests(first: 30, headRefName: $branchName) {
totalCount
edges {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.