Skip to content

Commit e18f299

Browse files
bobfloatsroot
authored and
root
committed
Added support to push tags to remote
1 parent 1fa7eec commit e18f299

File tree

11 files changed

+328
-170
lines changed

11 files changed

+328
-170
lines changed

src/VersionControl/GitCommandBundle/GitCommands/Command/GitTagCommand.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public function getTags()
4141
foreach ($lines as $line){
4242
$tagEntities[] = new GitTag($line);
4343
}
44-
44+
45+
rsort($tagEntities);
46+
4547
return $tagEntities;
4648
}
4749

@@ -68,6 +70,21 @@ public function createAnnotatedTag($version, $message, $commitShortCode = false
6870

6971
return $output;
7072
}
73+
74+
/**
75+
* Push specified tag to the remote repository.
76+
*
77+
* @param remote $remote The remote server to push to eg origin
78+
* @param string $tag The tag to push to the remote server eg v0.1.0
79+
*
80+
* @return string command response
81+
*/
82+
public function pushTag($remote, $tag)
83+
{
84+
$command = sprintf('git push %s %s', escapeshellarg(trim($remote)), escapeshellarg(trim($tag)));
85+
86+
return $this->command->runCommand($command);
87+
}
7188

7289

7390

src/VersionControl/GitControlBundle/Controller/Base/BaseProjectController.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
1818
use Symfony\Component\DependencyInjection\ContainerInterface;
1919
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
20+
use Symfony\Component\HttpFoundation\JsonResponse;
2021

2122
/**
2223
* Base Project controller.
@@ -174,4 +175,34 @@ public function setProjectGrantType($projectGrantType)
174175

175176
return $this;
176177
}
178+
179+
/**
180+
* Handle response types.
181+
*
182+
* @param \Symfony\Component\HttpFoundation\Response|string|array $content
183+
* @param string $responseType json|null
184+
* @param bool $success
185+
*
186+
* @return \FlashCardBundle\Controller\Secure\JsonResponse|\Symfony\Component\HttpFoundation\Response
187+
*/
188+
protected function viewHandler($content, $responseType, $success)
189+
{
190+
if ($responseType === 'json') {
191+
$data = ['success' => $success];
192+
if (is_array($content)) {
193+
$data = array_merge($data, $content);
194+
} elseif ($content instanceof \Symfony\Component\HttpFoundation\Response) {
195+
$data['form'] = $content->getContent();
196+
} else {
197+
$data['form'] = $content;
198+
}
199+
200+
return new JsonResponse(
201+
$data,
202+
($success ? 200 : 400)
203+
);
204+
} else {
205+
return $content;
206+
}
207+
}
177208
}

src/VersionControl/GitControlBundle/Controller/ProjectTagController.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,94 @@ private function createNewTagForm($project, $defaultData = array(), $formAction
122122

123123
return $form;
124124
}
125+
126+
127+
/**
128+
* Form to handle pushing tags to remote
129+
*
130+
* @Route("/push/{tag}/{responseType}", name="project_push_tag", defaults={"responseType" = null})
131+
* @Method({"GET", "POST"})
132+
* @Template()
133+
* @ProjectAccess(grantType="MASTER")
134+
*/
135+
public function pushTagAction(Request $request, $tag, $responseType)
136+
{
137+
$success = true;
138+
$form = $this->createPushTagForm($this->project,$tag);
139+
$form->add('push', SubmitType::class, array('label' => 'Push'));
140+
141+
$form->handleRequest($request);
142+
143+
if ($form->isSubmitted()) {
144+
if ($form->isValid()) {
145+
$formData = $form->getData();
146+
$remote = $formData['remote'];
147+
$tag = $formData['tag'];
148+
149+
try {
150+
$response = $this->gitCommands->command('tag')->pushTag($remote, $tag);
151+
152+
$this->get('session')->getFlashBag()->add('notice', $response);
153+
} catch (\Exception $e) {
154+
$this->get('session')->getFlashBag()->add('error', $e->getMessage());
155+
}
156+
157+
//return $this->redirect($this->generateUrl('project_push', array('id' => $id)));
158+
$data = ['redirect' => $this->generateUrl('project_tags', array('id' => $this->project->getId()))];
159+
160+
return $this->viewHandler($data, 'json', true);
161+
162+
} else {
163+
$success = false;
164+
}
165+
}
166+
167+
//Remote Server choice
168+
$gitRemoteVersions = $this->gitCommands->command('sync')->getRemoteVersions();
169+
170+
$content = $this->render('VersionControlGitControlBundle:ProjectTag:pushTag.html.twig',
171+
array_merge($this->viewVariables, array(
172+
'remoteVersions' => $gitRemoteVersions,
173+
'push_form' => $form->createView()
174+
)
175+
));
176+
177+
return $this->viewHandler($content, $responseType, $success);
178+
}
179+
180+
/**
181+
* Creates a form to edit a Project entity.
182+
*
183+
* @param Project $project The entity
184+
*
185+
* @return \Symfony\Component\Form\Form The form
186+
*/
187+
private function createPushTagForm($project, $tag)
188+
{
189+
//Remote Server choice
190+
$gitRemoteVersions = $this->gitCommands->command('sync')->getRemoteVersions();
191+
$remoteChoices = array();
192+
foreach ($gitRemoteVersions as $remoteVersion) {
193+
$remoteChoices[$remoteVersion[0].'('.$remoteVersion[1].')'] = $remoteVersion[0];
194+
}
195+
196+
$firstOrigin = reset($remoteChoices);
197+
198+
$defaultData = array('tag' => $tag);
199+
200+
$form = $this->createFormBuilder($defaultData, array(
201+
'action' => $this->generateUrl('project_push_tag', array('id' => $project->getId(), 'tag'=> $tag, 'responseType' => 'json')),
202+
'method' => 'POST',
203+
))
204+
->add('remote', ChoiceType::class, array(
205+
'label' => 'Remote Server', 'choices' => $remoteChoices, 'data' => $firstOrigin, 'required' => false, 'choices_as_values' => true, 'constraints' => array(
206+
new NotBlank(),
207+
), )
208+
)
209+
->add('tag', HiddenType::class)
210+
->getForm();
211+
212+
return $form;
213+
}
125214

126215
}

src/VersionControl/GitControlBundle/Resources/public/js/ajaxifypage.js

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,38 +48,39 @@ $(function(){
4848

4949
/* Ajaxify all Forms in container*/
5050
$contentContainter.on('submit', 'form', function (e) {
51+
if($(this).hasClass('ajaxify') == false){
52+
e.preventDefault();
53+
var loadingText = 'Submitting Form...';
54+
if($(this).data('masklabel')){
55+
loadingText = $(this).data('masklabel');
56+
}
5157

52-
e.preventDefault();
53-
var loadingText = 'Submitting Form...';
54-
if($(this).data('masklabel')){
55-
loadingText = $(this).data('masklabel');
56-
}
57-
58-
//hide modals if open
59-
$(".modal.in").modal('hide');
58+
//hide modals if open
59+
$(".modal.in").modal('hide');
6060

61-
$contentContainter.mask({label:loadingText});
62-
//loadUrl($(this).attr('action'));
63-
console.log(buttonClicked);
64-
var formData = $(this).serializeArray();
65-
formData.push( {'name':buttonClicked});
66-
$.ajax({
67-
type: $(this).attr('method'),
68-
url: $(this).attr('action'),
69-
data: formData,
70-
dataType: "html",
71-
success: function(data, textStatus, jqXHR) {
72-
$contentContainter.html(data);
73-
$contentContainter.unmask();
74-
console.log(textStatus);
75-
console.log(jqXHR);
76-
},
77-
error: function(e)
78-
{
79-
$contentContainter.html(e);
80-
$contentContainter.unmask();
81-
}
82-
});
61+
$contentContainter.mask({label:loadingText});
62+
//loadUrl($(this).attr('action'));
63+
console.log(buttonClicked);
64+
var formData = $(this).serializeArray();
65+
formData.push( {'name':buttonClicked});
66+
$.ajax({
67+
type: $(this).attr('method'),
68+
url: $(this).attr('action'),
69+
data: formData,
70+
dataType: "html",
71+
success: function(data, textStatus, jqXHR) {
72+
$contentContainter.html(data);
73+
$contentContainter.unmask();
74+
console.log(textStatus);
75+
console.log(jqXHR);
76+
},
77+
error: function(e)
78+
{
79+
$contentContainter.html(e);
80+
$contentContainter.unmask();
81+
}
82+
});
83+
}
8384
});
8485

8586
/**

src/VersionControl/GitControlBundle/Resources/public/js/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
$(function(){
44

5+
GlobalModal.initModal();
6+
57
$('body').on('click','#commit-select-all',function(){
68
$('.commit-file').prop( "checked", true );
79
});
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
var GlobalModal = function () {
2+
3+
return {
4+
5+
/**
6+
* Makes a link open in a modal. Link must contain data-form-modal.
7+
* If you want to set the header of modal add data-header="" to link
8+
* It also ajaxify a form
9+
*
10+
* @returns {undefined}
11+
*/
12+
initModal : function(){
13+
var self = this;
14+
//Sets Popup Modal for links with data-form-modal
15+
$('body').on('click', 'a[data-form-modal]', function (ev) {
16+
ev.preventDefault();
17+
var href = $(this).attr('href')
18+
, confirmHeader = $(this).data('header') ? $(this).data('header') : 'Submit Form'
19+
, size = $(this).data('modal-large') ? true : false;
20+
21+
self.triggerModalOpen(href,confirmHeader,size);
22+
23+
return false;
24+
});
25+
26+
var $contentContainter = $('body');
27+
28+
$contentContainter.on('submit', 'form.ajaxify', function (e) {
29+
e.preventDefault();
30+
var loadingText = 'Submitting Form...';
31+
if ($(this).data('masklabel')) {
32+
loadingText = $(this).data('masklabel');
33+
}
34+
35+
$contentContainter.mask({label: loadingText});
36+
37+
var $form = $(this);
38+
$.ajax({
39+
type: $form.attr('method'),
40+
url: $form.attr('action'),
41+
data: new FormData(this),
42+
dataType: "json",
43+
processData: false, // Don't process the files
44+
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
45+
cache: false,
46+
success: function (data) {
47+
console.log(data);
48+
if(data.redirect){
49+
location = data.redirect;
50+
}else if(data.modalContent){
51+
$('#dataFormModal .form-content').html(data.modalContent);
52+
}else{
53+
location.reload();
54+
}
55+
56+
//$contentContainter.unmask();
57+
//$(".modal.in").modal('hide');
58+
},
59+
error: function (jqXHR, textStatus, errorThrown) {
60+
if (typeof jqXHR.responseJSON !== 'undefined') {
61+
if (jqXHR.responseJSON.hasOwnProperty('form')) {
62+
$('#dataFormModal .form-content').html(jqXHR.responseJSON.form);
63+
}
64+
//$('.form_error').html(jqXHR.responseJSON.message);
65+
} else {
66+
alert(errorThrown);
67+
}
68+
$contentContainter.unmask();
69+
70+
}
71+
});
72+
});
73+
74+
}
75+
76+
,triggerModalOpen : function(href,header,large){
77+
$(".modal.in").modal('hide');
78+
79+
var sizeClass = large?'modal-lg':'';
80+
81+
$('#dataFormModal').remove();
82+
if (!$('#dataFormModal').length) {
83+
$('body').append('<div id="dataFormModal" class="modal " role="dialog" aria-labelledby="dataFormLabel" aria-hidden="true">\n\
84+
<div class="modal-dialog '+sizeClass+'" role="document">\n\
85+
<div class="modal-content">\n\
86+
<div class="modal-header">\n\
87+
<button aria-hidden="true" data-dismiss="modal" class="close" type="button">×</button>\n\
88+
<h4 id="dataFormHeader" class="modal-title">' + header + '</h4>\n\
89+
</div>\n\
90+
<div class="form-content">\n\
91+
<div class="modal-body">Loading...</div>\n\
92+
</div>\n\
93+
</div>\n\
94+
</div></div>');
95+
}
96+
$('#dataFormModal').find('.form-content').load(href,function(){
97+
98+
});
99+
100+
$('#dataFormModal').modal({show: true});
101+
}
102+
103+
};
104+
105+
}();
106+
107+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<div class="box-body">
2+
{% if(remoteVersions|length == 0)%}
3+
<div class="alert alert-warning" role="alert">
4+
You do not have any remote servers set up for this repository.
5+
</div>
6+
{% else %}
7+
8+
{{ form_start(push_form,{ 'attr': { 'class': 'form ajaxify','data-masklabel': 'Pushing changes to remote repository...'}}) }}
9+
10+
{{ form_errors(push_form) }}
11+
12+
<div class="form-group">
13+
{{ form_label(push_form.remote) }}
14+
{{ form_errors(push_form.remote) }}
15+
{{ form_widget(push_form.remote,{ 'attr': { 'class': 'form-control', 'placeholder':'Please select a remote repository'}}) }}
16+
</div>
17+
18+
<div class="text-right">
19+
<button class="btn btn-default" data-dismiss="modal" >Cancel</button>
20+
{{ form_widget(push_form.push, { 'attr': {'class': 'btn btn-success submit'} }) }}
21+
</div>
22+
{{ form_end(push_form) }}
23+
{% endif %}
24+
</div><!-- /.box-body -->
25+

0 commit comments

Comments
 (0)