Merge branch 'noname' into 'master'

Don't require versionName

See merge request fdroid/fdroidserver!1265
This commit is contained in:
Hans-Christoph Steiner
2025-12-11 18:00:41 +00:00
8 changed files with 148 additions and 75 deletions

View File

@@ -277,7 +277,7 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
message = "Timeout exceeded! Build VM force-stopped for {0}:{1}"
else:
message = "Build.py failed on server for {0}:{1}"
raise BuildException(message.format(app.id, build.versionName),
raise BuildException(message.format(app.id, build.versionCode),
str(output, 'utf-8', 'replace'))
# Retreive logs...
@@ -304,7 +304,7 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
except Exception as exc:
raise BuildException(
"Build failed for {0}:{1} - missing output files".format(
app.id, build.versionName), str(output, 'utf-8', 'replace')) from exc
app.id, build.versionCode), str(output, 'utf-8', 'replace')) from exc
ftp.close()
finally:
@@ -480,18 +480,18 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
p = FDroidPopen(['sudo', 'DEBIAN_FRONTEND=noninteractive',
'bash', '-e', '-u', '-o', 'pipefail', '-x', '-c', '; '.join(build.sudo)])
if p.returncode != 0:
raise BuildException("Error running sudo command for %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException("Error running sudo command for %s:%d" %
(app.id, build.versionCode), p.output)
p = FDroidPopen(['sudo', 'passwd', '--lock', 'root'])
if p.returncode != 0:
raise BuildException("Error locking root account for %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException("Error locking root account for %s:%d" %
(app.id, build.versionCode), p.output)
p = FDroidPopen(['sudo', 'SUDO_FORCE_REMOVE=yes', 'dpkg', '--purge', 'sudo'])
if p.returncode != 0:
raise BuildException("Error removing sudo for %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException("Error removing sudo for %s:%d" %
(app.id, build.versionCode), p.output)
log_path = os.path.join(log_dir,
common.get_toolsversion_logname(app, build))
@@ -499,8 +499,8 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
f.write(common.get_android_tools_version_log())
else:
if build.sudo:
logging.warning('%s:%s runs this on the buildserver with sudo:\n\t%s\nThese commands were skipped because fdroid build is not running on a dedicated build server.'
% (app.id, build.versionName, build.sudo))
logging.warning('%s:%d runs this on the buildserver with sudo:\n\t%s\nThese commands were skipped because fdroid build is not running on a dedicated build server.'
% (app.id, build.versionCode, build.sudo))
# Prepare the source code...
root_dir, srclibpaths = common.prepare_source(vcs, app, build,
@@ -551,8 +551,8 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
p = FDroidPopen(['ant', 'clean'], cwd=root_dir)
if p is not None and p.returncode != 0:
raise BuildException("Error cleaning %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException("Error cleaning %s:%d" %
(app.id, build.versionCode), p.output)
for root, dirs, files in os.walk(build_dir):
@@ -629,8 +629,8 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
p = FDroidPopen(['bash', '-e', '-u', '-o', 'pipefail', '-x', '-c', cmd], cwd=root_dir)
if p.returncode != 0:
raise BuildException("Error running build command for %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException("Error running build command for %s:%d" %
(app.id, build.versionCode), p.output)
# Build native stuff if required...
if build.buildjni and build.buildjni != ['no']:
@@ -658,7 +658,7 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
del manifest_text
p = FDroidPopen(cmd, cwd=os.path.join(root_dir, d))
if p.returncode != 0:
raise BuildException("NDK build failed for %s:%s" % (app.id, build.versionName), p.output)
raise BuildException("NDK build failed for %s:%d" % (app.id, build.versionCode), p.output)
p = None
# Build the release...
@@ -716,10 +716,8 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
commit_id = build.commit
if p is not None and p.returncode != 0:
raise BuildException("Build failed for %s:%s@%s" % (app.id, build.versionName, commit_id),
raise BuildException("Build failed for %s:%d@%s" % (app.id, build.versionCode, commit_id),
p.output)
logging.info("Successfully built version {versionName} of {appid} from {commit_id}"
.format(versionName=build.versionName, appid=app.id, commit_id=commit_id))
omethod = build.output_method()
if omethod == 'maven':
@@ -820,13 +818,15 @@ def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, ext
raise BuildException("Unsigned APK is not at expected location of " + src)
if common.get_file_extension(src) == 'apk':
vercode, version = get_metadata_from_apk(app, build, src)
if version != build.versionName or vercode != build.versionCode:
raise BuildException(("Unexpected version/version code in output;"
" APK: '%s' / '%d', "
" Expected: '%s' / '%d'")
% (version, vercode, build.versionName,
build.versionCode))
versionCode, _ignored = get_metadata_from_apk(app, build, src)
if versionCode != build.versionCode:
raise BuildException(("Unexpected versionCode in output;"
" APK: '%d', "
" Expected: '%d'")
% (versionCode, build.versionCode))
logging.info(f"Successfully built {app.id}:{versionCode} from {commit_id}")
if (options.scan_binary or config.get('scan_binary')) and not options.skipscan:
if scanner.scan_binary(src):
raise BuildException("Found blocklisted packages in final apk!")
@@ -914,8 +914,7 @@ def trybuild(app, build, build_dir, output_dir, log_dir, also_check_dir,
if build.disable and not options.force:
return False
logging.info("Building version %s (%s) of %s" % (
build.versionName, build.versionCode, app.id))
logging.info(f"Building {app.id}:{build.versionCode}")
if server:
# When using server mode, still keep a local cache of the repo, by
@@ -1309,8 +1308,8 @@ def main():
tstamp = time.strftime("%Y-%m-%d %H:%M:%SZ", time.gmtime())
with open(os.path.join(log_dir, appid + '.log'), 'a+') as f:
f.write('\n\n============================================================\n')
f.write('versionCode: %s\nversionName: %s\ncommit: %s\n' %
(build.versionCode, build.versionName, build.commit))
f.write('versionCode: %s\ncommit: %s\n' %
(build.versionCode, build.commit))
f.write('Build completed at '
+ tstamp + '\n')
f.write('\n' + tools_version_log + '\n')

View File

@@ -425,10 +425,6 @@ def _getappname(app: metadata.App) -> str:
return common.get_app_display_name(app)
def _getcvname(app: metadata.App) -> str:
return '%s (%s)' % (app.CurrentVersion, app.CurrentVersionCode)
def fetch_autoname(app: metadata.App, tag: str) -> Optional[str]:
"""Fetch AutoName.
@@ -587,9 +583,8 @@ def checkupdates_app(app: metadata.App, auto: bool, commit: bool = False) -> Non
if updating:
name = _getappname(app)
ver = _getcvname(app)
logging.info('...updating to version %s' % ver)
commitmsg = 'Update CurrentVersion of %s to %s' % (name, ver)
logging.info('...updating to version %d' % app.CurrentVersionCode)
commitmsg = 'Update CurrentVersionCode of %s to %d' % (name, app.CurrentVersionCode)
if auto:
mode = app.AutoUpdateMode
@@ -651,22 +646,23 @@ def checkupdates_app(app: metadata.App, auto: bool, commit: bool = False) -> Non
for b, v in zip(newbuilds, vercodes):
b.disable = False
b.versionCode = v
b.versionName = app.CurrentVersion + suffix.replace(
'%c', str(v)
)
logging.info("...auto-generating build for " + b.versionName)
if b.versionName and app.CurrentVersion:
b.versionName = app.CurrentVersion + suffix.replace(
'%c', str(v)
)
logging.info("...auto-generating build for " + str(b.versionCode))
if tag:
b.commit = tag
else:
commit = pattern.replace('%v', app.CurrentVersion)
if app.CurrentVersion:
commit = pattern.replace('%v', app.CurrentVersion)
commit = commit.replace('%c', str(v))
b.commit = commit
app['Builds'].extend(newbuilds)
name = _getappname(app)
ver = _getcvname(app)
commitmsg = "Update %s to %s" % (name, ver)
commitmsg = "Update %s to %s" % (name, app.CurrentVersionCode)
else:
raise MetaDataException(
_('Invalid AutoUpdateMode: {mode}').format(mode=mode)

View File

@@ -2714,8 +2714,7 @@ def prepare_source(
)
if p.returncode != 0:
raise BuildException(
"Error running init command for %s:%s" % (app.id, build.versionName),
p.output,
f"Error running init command for {app.id}:{build.versionCode}", p.output
)
# Apply patches if any
@@ -2811,6 +2810,9 @@ def prepare_source(
# Insert versionCode and number into the manifest if necessary
if build.forceversion:
if not build.versionName:
raise MetaDataException(_("forceversion requires versionName to be set"))
logging.info("Changing the versionName")
for path in manifest_paths(root_dir, flavors):
if not os.path.isfile(path):
@@ -2895,8 +2897,10 @@ def prepare_source(
['bash', '-e', '-u', '-o', 'pipefail', '-x', '-c', '--', cmd], cwd=root_dir
)
if p.returncode != 0:
raise BuildException("Error running prebuild command for %s:%s" %
(app.id, build.versionName), p.output)
raise BuildException(
f"Error running prebuild command for {app.id}:{build.versionCode}",
p.output,
)
# Generate (or update) the ant build file, build.xml...
if build.build_method() == 'ant' and build.androidupdate != ['no']:
@@ -3532,8 +3536,16 @@ def set_FDroidPopen_env(app=None, build=None):
def replace_build_vars(cmd, build):
cmd = cmd.replace('$$COMMIT$$', build.commit)
cmd = cmd.replace('$$VERSION$$', build.versionName)
cmd = cmd.replace('$$VERCODE$$', str(build.versionCode))
version_tag = '$$VERSION$$'
if build.get('versionName'):
cmd = cmd.replace(version_tag, build.versionName)
elif version_tag in cmd:
raise MetaDataException(
_("{tag} requires versionName to be set").format(tag=version_tag)
)
return cmd

View File

@@ -348,11 +348,9 @@ def main():
paths = get_all_gradle_and_manifests(tmp_importer_dir)
gradle_subdir = get_gradle_subdir(tmp_importer_dir, paths)
if paths:
versionName, versionCode, appid = common.parse_androidmanifests(paths, app)
_ignored, versionCode, appid = common.parse_androidmanifests(paths, app)
if not appid:
raise FDroidException(_("Couldn't find Application ID"))
if not versionName:
logging.warning(_('Could not find latest versionName'))
if not versionCode:
logging.warning(_('Could not find latest versionCode'))
else:
@@ -363,8 +361,6 @@ def main():
raise FDroidException(_('Package "{appid}" already exists').format(appid=appid))
# Create a build line...
build.versionName = versionName or 'Unknown'
app.CurrentVersion = build.versionName
build.versionCode = versionCode or 0
app.CurrentVersionCode = build.versionCode
if options.subdir:

View File

@@ -796,12 +796,15 @@ def make_v2(
for build in app.get('Builds', []):
if build['versionCode'] == package['versionCode']:
versionName = build.get('versionName')
logging.info(
_(
'Overriding blank versionName in {apkfilename} from metadata: {version}'
).format(apkfilename=package['apkName'], version=versionName)
)
package['versionName'] = versionName
if versionName:
logging.info(
_(
'Overriding blank versionName in {apkfilename} from metadata: {version}'
).format(
apkfilename=package['apkName'], version=versionName
)
)
package['versionName'] = versionName
break
if packageName in output_packages:
packagelist = output_packages[packageName]
@@ -1003,12 +1006,15 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, signer_fingerprints
for build in app.get('Builds', []):
if build['versionCode'] == package['versionCode']:
versionName = build.get('versionName')
logging.info(
_(
'Overriding blank versionName in {apkfilename} from metadata: {version}'
).format(apkfilename=package['apkName'], version=versionName)
)
package['versionName'] = versionName
if versionName:
logging.info(
_(
'Overriding blank versionName in {apkfilename} from metadata: {version}'
).format(
apkfilename=package['apkName'], version=versionName
)
)
package['versionName'] = versionName
break
if packageName in output_packages:
packagelist = output_packages[packageName]

View File

@@ -1898,7 +1898,7 @@ FILLING_UCMS = re.compile(r'^(Tags.*|RepoManifest.*)')
def check_checkupdates_ran(app):
if FILLING_UCMS.match(app.UpdateCheckMode):
if not app.AutoName and not app.CurrentVersion and app.CurrentVersionCode == 0:
if not app.AutoName and app.CurrentVersionCode == 0:
yield _(
"UpdateCheckMode is set but it looks like checkupdates hasn't been run yet."
)
@@ -1960,8 +1960,8 @@ def check_builds(app):
for s in ['master', 'main', 'origin', 'HEAD', 'default', 'develop', 'trunk']:
if build.commit and build.commit.startswith(s):
yield _(
"Branch '{branch}' used as commit in build '{versionName}'"
).format(branch=s, versionName=build.versionName)
"Branch '{branch}' used as commit in build '{versionCode}'"
).format(branch=s, versionCode=build.versionCode)
for srclib in build.srclibs:
if '@' in srclib:
ref = srclib.split('@')[1].split('/')[0]
@@ -2006,8 +2006,8 @@ def check_files_dir(app):
for build in app.get('Builds', []):
for fname in build.patch:
if fname not in files:
yield _("Unknown file '{filename}' in build '{versionName}'").format(
filename=fname, versionName=build.versionName
yield _("Unknown file '{filename}' in build '{versionCode}'").format(
filename=fname, versionCode=build.versionCode
)
else:
used.add(fname)
@@ -2068,8 +2068,8 @@ def check_extlib_dir(apps):
# Don't show error on archived versions
if i >= len(builds) - archive_policy:
yield _(
"{appid}: Unknown extlib {path} in build '{versionName}'"
).format(appid=app.id, path=path, versionName=build.versionName)
"{appid}: Unknown extlib {path} in build '{versionCode}'"
).format(appid=app.id, path=path, versionCode=build.versionCode)
else:
used.add(path)

View File

@@ -1285,12 +1285,12 @@ def main():
if build.disable and not options.force:
logging.info(
"...skipping version %s - %s"
% (build.versionName, build.get('disable', build.commit[1:]))
"...skipping versionCode %s - %s"
% (build.versionCode, build.get('disable', build.commit[1:]))
)
continue
logging.info("...scanning version " + build.versionName)
logging.info("...scanning versionCode " + build.versionCode)
# Prepare the source code...
common.prepare_source(
vcs, app, build, build_dir, srclib_dir, extlib_dir, False

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import base64
import difflib
import glob
import gzip
@@ -3780,3 +3781,66 @@ class CalculateMathStringTest(unittest.TestCase):
def test_calculate_math_string_error_comment(self):
with self.assertRaises(SyntaxError):
fdroidserver.common.calculate_math_string('1-1 # no comment')
class BuildVarsTest(unittest.TestCase):
def setUp(self):
self.build = fdroidserver.metadata.Build()
self.build.commit = 'deadcafebeef'
self.build.versionCode = 1
def test_replace_build_vars_empty(self):
testvalue = ''
self.assertEqual(
testvalue,
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_random(self):
length = 1024
testvalue = base64.b64encode(os.urandom(length)).decode('utf-8')[:length]
self.assertEqual(
testvalue,
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_non_var(self):
testvalue = '$$NOTANFDROIDVAR$$'
self.assertEqual(
testvalue,
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_commit(self):
testvalue = '$$COMMIT$$'
self.assertEqual(
self.build.commit,
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_versionCode(self):
testvalue = '$$VERCODE$$'
self.assertEqual(
str(self.build.versionCode),
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_versionName(self):
self.build.versionName = 'v1.0'
testvalue = '$$VERSION$$'
self.assertEqual(
self.build.versionName,
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_all(self):
self.build.versionName = 'v1.0'
testvalue = '$$COMMIT$$-$$VERCODE$$-$$VERSION$$'
self.assertEqual(
f'{self.build.commit}-{self.build.versionCode}-{self.build.versionName}',
fdroidserver.common.replace_build_vars(testvalue, self.build),
)
def test_replace_build_vars_no_versionName(self):
with self.assertRaises(fdroidserver.exception.MetaDataException):
fdroidserver.common.replace_build_vars('$$VERSION$$', self.build),