Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
R
Release
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Development
Release
Commits
7df2def4
Commit
7df2def4
authored
5 years ago
by
totten
Browse files
Options
Downloads
Patches
Plain Diff
glr - Pull down lib code via packagist
parent
192d2fb0
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
bin/glr
+27
-22
27 additions, 22 deletions
bin/glr
src/clippy.php
+0
-177
0 additions, 177 deletions
src/clippy.php
with
27 additions
and
199 deletions
bin/glr
+
27
−
22
View file @
7df2def4
...
...
@@ -6,55 +6,60 @@ namespace Clippy;
// Usage: ./glr upload <project-url> <version> <asset-files>*
// Example: ./glr https://lab.civicrm.org/foo/bar 1.2.3 foobar-1.2.3.zip
require
_once
pogo_script_dir
()
.
'/../src/clippy.php'
;
#!
require
totten/clippy: 0.1.0
#!require { mnapoli/silly: ~1.7, php: '>=7.0', g
uzzle
h
ttp
/guzzle: ~6.0 }
use
G
uzzle
H
ttp
\HandlerStack
;
use
Symfony\Component\Console\Style\SymfonyStyle
;
function
labProject
(
$project
,
$io
)
{
assertThat
(
preg_match
(
';https?://[^/]+/[^/]+/[^/]+;'
,
$project
),
"Project URL should match pattern: https:///DOMAIN/OWNER/REPO"
);
list
(
$scheme
,
,
$host
,
$owner
,
$repo
)
=
explode
(
'/'
,
$project
);
$c
=
clippy
()
->
register
(
plugins
());
$c
[
'gitlab()'
]
=
function
(
$url
,
Credentials
$cred
,
HandlerStack
$guzzleHandler
)
{
assertThat
(
preg_match
(
';https?://[^/]+/[^/]+/[^/]+;'
,
$url
),
"Project URL should match pattern: https:///DOMAIN/OWNER/REPO"
);
list
(
$scheme
,
,
$host
,
$owner
,
$repo
)
=
explode
(
'/'
,
$url
);
$
lab
=
new
\GuzzleHttp\Client
([
$
client
=
new
\GuzzleHttp\Client
([
'base_uri'
=>
"
{
$scheme
}
//
{
$host
}
/api/v4/projects/
{
$owner
}
%2F
{
$repo
}
/"
,
'headers'
=>
[
'PRIVATE-TOKEN'
=>
assertVal
(
cred
(
'PRIVATE_TOKEN'
,
$host
,
$io
),
'Missing PRIVATE_TOKEN'
),
],
'headers'
=>
[
'PRIVATE-TOKEN'
=>
$cred
->
get
(
'PRIVATE_TOKEN'
,
$host
)],
'handler'
=>
$guzzleHandler
,
]);
return
$
lab
;
}
return
$
client
;
}
;
$app
=
new
\Silly\Application
();
$app
->
command
(
'upload projectUrl verNum assets*'
,
function
(
$projectUrl
,
$verNum
,
$assets
,
SymfonyStyle
$io
)
{
$labProject
=
labProject
(
$projectUrl
,
$io
);
$c
[
'app'
]
->
command
(
'upload [-N|--dry-run] projectUrl verNum assets*'
,
function
(
$projectUrl
,
$verNum
,
$assets
,
SymfonyStyle
$io
,
$gitlab
,
$input
)
{
$verbose
=
function
(
$data
)
use
(
$io
)
{
return
$io
->
isVerbose
()
?
toJSON
(
$data
)
:
''
;
};
$client
=
$gitlab
(
$projectUrl
);
assertThat
(
preg_match
(
'/^\d[0-9a-z\.\-\+]*$/'
,
$verNum
));
$io
->
writeln
(
sprintf
(
"<info>Release project <comment>%s</comment> at version <comment>%s</comment>:
\n
<comment> * %s</comment></info>"
,
$projectUrl
,
$verNum
,
implode
(
"
\n
* "
,
$assets
)));
$existingAssets
=
fromJSON
(
$
labProjec
t
->
get
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links'
));
$existingAssets
=
fromJSON
(
$
clien
t
->
get
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links'
));
$existingAssets
=
index
([
'name'
],
$existingAssets
);
foreach
(
$assets
as
$asset
)
{
assertThat
(
file_exists
(
$asset
),
"File
$asset
does not exist"
);
$upload
=
fromJSON
(
$labProject
->
post
(
'uploads'
,
[
if
(
$input
->
getOption
(
'dry-run'
))
{
$io
->
note
(
"(DRY-RUN) Skipped upload of
$asset
"
);
continue
;
}
$upload
=
fromJSON
(
$client
->
post
(
'uploads'
,
[
'multipart'
=>
[
[
'name'
=>
'file'
,
'contents'
=>
fopen
(
$asset
,
'r'
)],
],
]));
$io
->
writeln
(
"<info>Created new upload
:
</info>
\n
"
.
toJSON
(
$upload
));
$io
->
writeln
(
"<info>Created new upload</info>
"
.
$verbose
(
$upload
));
if
(
isset
(
$existingAssets
[
basename
(
$asset
)]))
{
$delete
=
fromJSON
(
$
labProjec
t
->
delete
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links/'
.
$existingAssets
[
basename
(
$asset
)][
'id'
]));
$io
->
writeln
(
"<info>Deleted old upload
:
</info>
\n
"
.
toJSON
(
$delete
));
$delete
=
fromJSON
(
$
clien
t
->
delete
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links/'
.
$existingAssets
[
basename
(
$asset
)][
'id'
]));
$io
->
writeln
(
"<info>Deleted old upload</info>
"
.
$verbose
(
$delete
));
// Should we also delete the previous upload? Is that possible?
}
$release
=
fromJSON
(
$
labProjec
t
->
post
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links'
,
[
$release
=
fromJSON
(
$
clien
t
->
post
(
'releases/'
.
urlencode
(
$verNum
)
.
'/assets/links'
,
[
'form_params'
=>
[
'name'
=>
basename
(
$asset
),
'url'
=>
joinUrl
(
$projectUrl
,
$upload
[
'url'
]),
],
]));
$io
->
writeln
(
"<info>Updated release
:
</info>
\n
"
.
toJSON
(
$release
));
$io
->
writeln
(
"<info>Updated release</info>
"
.
$verbose
(
$release
));
}
});;
$app
->
run
();
$
c
[
'
app
'
]
->
run
();
This diff is collapsed.
Click to expand it.
src/clippy.php
deleted
100644 → 0
+
0
−
177
View file @
192d2fb0
<?php
namespace
Clippy
;
use
Symfony\Component\Console\Style\SymfonyStyle
;
// -----------------------------------------------------------------------------
// Assertions
/**
* Assert that $bool is true.
*
* @param bool $bool
* @param string $msg
* @throws \Exception
*/
function
assertThat
(
$bool
,
$msg
=
''
)
{
if
(
!
$bool
)
{
throw
new
\Exception
(
$msg
?
$msg
:
'Assertion failed'
);
}
}
/**
* Assert that $value has an actual value (not null or empty-string)
*
* @param mixed $value
* @param string $msg
* @return mixed
* The approved value
* @throws \Exception
*/
function
assertVal
(
$value
,
$msg
)
{
if
(
$value
===
NULL
||
$value
===
''
)
{
throw
new
\Exception
(
$msg
?
$msg
:
'Missing expected value'
);
}
return
$value
;
}
function
fail
(
$msg
)
{
throw
new
\Exception
(
$msg
?
$msg
:
'Assertion failed'
);
}
// -----------------------------------------------------------------------------
// IO utilities
/**
* Combine all elements of part, in order, to form a string - using path delimiters.
* Duplicate delimiters are trimmed.
*
* @param array $parts
* A list of strings and/or arrays.
* @return string
*/
function
joinPath
(...
$parts
)
{
$path
=
[];
foreach
(
$parts
as
$part
)
{
if
(
is_array
(
$part
))
{
$path
=
array_merge
(
$path
,
$part
);
}
else
{
$path
[]
=
$part
;
}
}
$result
=
implode
(
DIRECTORY_SEPARATOR
,
$parts
);
$both
=
"[
\\
/]"
;
return
preg_replace
(
";
{
$both
}{
$both
}
+;"
,
'/'
,
$result
);
}
/**
* Combine all elements of part, in order, to form a string - using URL delimiters.
* Duplicate delimiters are trimmed.
*
* @param array $parts
* A list of strings and/or arrays.
* @return string
*/
function
joinUrl
(...
$parts
)
{
$path
=
[];
foreach
(
$parts
as
$part
)
{
if
(
is_array
(
$part
))
{
$path
=
array_merge
(
$path
,
$part
);
}
else
{
$path
[]
=
$part
;
}
}
$result
=
implode
(
'/'
,
$parts
);
return
preg_replace
(
';//+;'
,
'/'
,
$result
);
}
function
toJSON
(
$data
)
{
return
json_encode
(
$data
,
JSON_PRETTY_PRINT
|
JSON_UNESCAPED_SLASHES
);
}
function
fromJSON
(
$data
)
{
#!require psr/http-message: *
if
(
$data
instanceof
\Psr\Http\Message\ResponseInterface
)
{
$data
=
$data
->
getBody
()
->
getContents
();
}
assertThat
(
is_string
(
$data
));
$result
=
json_decode
(
$data
,
1
);
assertThat
(
$result
!==
NULL
||
$data
===
'null'
,
sprintf
(
"JSON parse error:
\n
----
\n
%s
\n
----
\n
"
,
$data
));
return
$result
;
}
// -----------------------------------------------------------------------------
// Array utilities
/**
* Builds an array-tree which indexes the records in an array.
*
* @param string[] $keys
* Properties by which to index.
* @param object|array $records
*
* @return array
* Multi-dimensional array, with one layer for each key.
*/
function
index
(
$keys
,
$records
)
{
$final_key
=
array_pop
(
$keys
);
$result
=
[];
foreach
(
$records
as
$record
)
{
$node
=
&
$result
;
foreach
(
$keys
as
$key
)
{
if
(
is_array
(
$record
))
{
$keyvalue
=
isset
(
$record
[
$key
])
?
$record
[
$key
]
:
NULL
;
}
else
{
$keyvalue
=
isset
(
$record
->
{
$key
})
?
$record
->
{
$key
}
:
NULL
;
}
if
(
isset
(
$node
[
$keyvalue
])
&&
!
is_array
(
$node
[
$keyvalue
]))
{
$node
[
$keyvalue
]
=
[];
}
$node
=
&
$node
[
$keyvalue
];
}
if
(
is_array
(
$record
))
{
$node
[
$record
[
$final_key
]]
=
$record
;
}
else
{
$node
[
$record
->
{
$final_key
}]
=
$record
;
}
}
return
$result
;
}
// -----------------------------------------------------------------------------
// Higher level services
/**
* @param string $name
* Environment variable
* @param string $context
* @param \Symfony\Component\Console\Style\SymfonyStyle|NULL $io
* @return mixed|null|string
*/
function
cred
(
$name
,
$context
=
'default'
,
SymfonyStyle
$io
=
NULL
)
{
if
(
getenv
(
$name
))
{
return
getenv
(
$name
);
}
$storage
=
joinPath
(
getenv
(
'HOME'
),
'.config'
,
'clippy-cred'
,
urlencode
(
$context
)
.
'.json'
);
if
(
file_exists
(
$storage
))
{
$data
=
fromJSON
(
file_get_contents
(
$storage
));
if
(
isset
(
$data
[
$name
]))
{
return
$data
[
$name
];
}
}
if
(
$io
)
{
if
(
$storage
)
{
$io
->
note
(
"Credential
$name
not found in environment"
);
$io
->
note
(
"Credential
$name
not found in
$storage
"
);
}
$pass
=
$io
->
askHidden
(
sprintf
(
'Please enter credential %s for %s:'
,
$name
,
$context
));
// TODO save
return
$pass
;
}
return
NULL
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment