Merge #88 Resolve HEAD in ksurl to actual hash
This commit is contained in:
commit
81e90eb780
@ -507,7 +507,8 @@ Image Build Settings
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Config can contain anything what is accepted by
|
Config can contain anything what is accepted by
|
||||||
koji image-build --config configfile.ini
|
``koji image-build --config configfile.ini``
|
||||||
|
|
||||||
Repo is currently the only option which is being automatically transformed
|
Repo is currently the only option which is being automatically transformed
|
||||||
into a string.
|
into a string.
|
||||||
|
|
||||||
@ -515,6 +516,10 @@ Image Build Settings
|
|||||||
The 'format' attr is [('image_type', 'image_suffix'), ...].
|
The 'format' attr is [('image_type', 'image_suffix'), ...].
|
||||||
productmd should ideally contain all of image types and suffixes.
|
productmd should ideally contain all of image types and suffixes.
|
||||||
|
|
||||||
|
If ``ksurl`` ends with ``#HEAD``, Pungi will figure out the SHA1 hash of
|
||||||
|
current HEAD and use that instead.
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
::
|
::
|
||||||
@ -528,6 +533,7 @@ Example
|
|||||||
'target': 'koji-target-name',
|
'target': 'koji-target-name',
|
||||||
'ksversion': 'F23', # value from pykickstart
|
'ksversion': 'F23', # value from pykickstart
|
||||||
'version': '23',
|
'version': '23',
|
||||||
|
# correct SHA1 hash will be put into the URL below automatically
|
||||||
'ksurl': 'https://git.fedorahosted.org/git/spin-kickstarts.git?somedirectoryifany#HEAD',
|
'ksurl': 'https://git.fedorahosted.org/git/spin-kickstarts.git?somedirectoryifany#HEAD',
|
||||||
'kickstart': "fedora-docker-base.ks",
|
'kickstart': "fedora-docker-base.ks",
|
||||||
'repo': ["http://someextrarepos.org/repo", "ftp://rekcod.oi/repo].
|
'repo': ["http://someextrarepos.org/repo", "ftp://rekcod.oi/repo].
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from pungi.util import get_arch_variant_data
|
from pungi.util import get_arch_variant_data, resolve_git_url
|
||||||
from pungi.phases.base import PhaseBase
|
from pungi.phases.base import PhaseBase
|
||||||
from pungi.linker import Linker
|
from pungi.linker import Linker
|
||||||
from pungi.paths import translate_path
|
from pungi.paths import translate_path
|
||||||
@ -34,6 +34,9 @@ class ImageBuildPhase(PhaseBase):
|
|||||||
for variant in self.compose.get_variants(arch=arch):
|
for variant in self.compose.get_variants(arch=arch):
|
||||||
image_build_data = get_arch_variant_data(self.compose.conf, self.name, arch, variant)
|
image_build_data = get_arch_variant_data(self.compose.conf, self.name, arch, variant)
|
||||||
for image_conf in image_build_data:
|
for image_conf in image_build_data:
|
||||||
|
# Replace possible ambiguous ref name with explicit hash.
|
||||||
|
if 'ksurl' in image_conf:
|
||||||
|
image_conf['ksurl'] = resolve_git_url(image_conf['ksurl'])
|
||||||
image_conf["arches"] = arch # passed to get_image_build_cmd as dict
|
image_conf["arches"] = arch # passed to get_image_build_cmd as dict
|
||||||
image_conf["variant"] = variant # ^
|
image_conf["variant"] = variant # ^
|
||||||
image_conf["install_tree"] = translate_path(self.compose, self.compose.paths.compose.os_tree(arch, variant)) # ^
|
image_conf["install_tree"] = translate_path(self.compose, self.compose.paths.compose.os_tree(arch, variant)) # ^
|
||||||
|
@ -23,6 +23,7 @@ import hashlib
|
|||||||
import errno
|
import errno
|
||||||
import pipes
|
import pipes
|
||||||
import re
|
import re
|
||||||
|
import urlparse
|
||||||
|
|
||||||
from kobo.shortcuts import run
|
from kobo.shortcuts import run
|
||||||
from productmd.common import get_major_version
|
from productmd.common import get_major_version
|
||||||
@ -214,6 +215,32 @@ def get_arch_variant_data(conf, var_name, arch, variant):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_git_url(url):
|
||||||
|
"""Given a url to a Git repo specifying HEAD as a ref, replace that
|
||||||
|
specifier with actual SHA1 of the commit.
|
||||||
|
|
||||||
|
Otherwise, the original URL will be returned.
|
||||||
|
|
||||||
|
Raises RuntimeError if there was an error. Most likely cause is failure to
|
||||||
|
run git command.
|
||||||
|
"""
|
||||||
|
r = urlparse.urlsplit(url)
|
||||||
|
if r.fragment != 'HEAD':
|
||||||
|
return url
|
||||||
|
|
||||||
|
baseurl = urlparse.urlunsplit((r.scheme, r.netloc, r.path, '', ''))
|
||||||
|
_, output = run(['git', 'ls-remote', baseurl, r.fragment])
|
||||||
|
|
||||||
|
lines = [line for line in output.split('\n') if line]
|
||||||
|
if len(lines) != 1:
|
||||||
|
# This should never happen. HEAD can not match multiple commits in a
|
||||||
|
# single repo, and there can not be a repo without a HEAD.
|
||||||
|
raise RuntimeError('Failed to resolve %s', url)
|
||||||
|
|
||||||
|
fragment = lines[0].split()[0]
|
||||||
|
return urlparse.urlunsplit((r.scheme, r.netloc, r.path, r.query, fragment))
|
||||||
|
|
||||||
|
|
||||||
# fomat: {arch|*: [data]}
|
# fomat: {arch|*: [data]}
|
||||||
def get_arch_data(conf, var_name, arch):
|
def get_arch_data(conf, var_name, arch):
|
||||||
result = []
|
result = []
|
||||||
|
50
tests/test_util.py
Executable file
50
tests/test_util.py
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
|
||||||
|
from pungi import util
|
||||||
|
|
||||||
|
|
||||||
|
class TestGitRefResolver(unittest.TestCase):
|
||||||
|
|
||||||
|
@mock.patch('pungi.util.run')
|
||||||
|
def test_successful_resolve(self, run):
|
||||||
|
run.return_value = (0, 'CAFEBABE\tHEAD\n')
|
||||||
|
|
||||||
|
url = util.resolve_git_url('https://git.example.com/repo.git?somedir#HEAD')
|
||||||
|
|
||||||
|
self.assertEqual(url, 'https://git.example.com/repo.git?somedir#CAFEBABE')
|
||||||
|
run.assert_called_once_with(['git', 'ls-remote', 'https://git.example.com/repo.git', 'HEAD'])
|
||||||
|
|
||||||
|
@mock.patch('pungi.util.run')
|
||||||
|
def test_resolve_missing_spec(self, run):
|
||||||
|
url = util.resolve_git_url('https://git.example.com/repo.git')
|
||||||
|
|
||||||
|
self.assertEqual(url, 'https://git.example.com/repo.git')
|
||||||
|
self.assertEqual(run.mock_calls, [])
|
||||||
|
|
||||||
|
@mock.patch('pungi.util.run')
|
||||||
|
def test_resolve_non_head_spec(self, run):
|
||||||
|
url = util.resolve_git_url('https://git.example.com/repo.git#some-tag')
|
||||||
|
|
||||||
|
self.assertEqual(url, 'https://git.example.com/repo.git#some-tag')
|
||||||
|
self.assertEqual(run.mock_calls, [])
|
||||||
|
|
||||||
|
@mock.patch('pungi.util.run')
|
||||||
|
def test_resolve_ambiguous(self, run):
|
||||||
|
run.return_value = (0, 'CAFEBABE\tF11\nDEADBEEF\tF10\n')
|
||||||
|
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
util.resolve_git_url('https://git.example.com/repo.git?somedir#HEAD')
|
||||||
|
|
||||||
|
run.assert_called_once_with(['git', 'ls-remote', 'https://git.example.com/repo.git', 'HEAD'])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user