diff --git a/.travis.yml b/.travis.yml index b89e9bfed..20d9211aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,7 +69,7 @@ jobs: directories: - $BUILD_DIR script: - - ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories Filter,Targeted,Purge,Serialization,WebApi,Utility,UriUtility,IO,ImportExport,Disruption,RestoreHandler + - ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories Filter,Targeted,Purge,Serialization,WebApi,Utility,UriUtility,IO,ImportExport,Disruption,RestoreHandler,RepairHandler - stage: tests cache: diff --git a/Duplicati/Library/AutoUpdater/UpdaterManager.cs b/Duplicati/Library/AutoUpdater/UpdaterManager.cs index 9f7f16377..8d7b90955 100644 --- a/Duplicati/Library/AutoUpdater/UpdaterManager.cs +++ b/Duplicati/Library/AutoUpdater/UpdaterManager.cs @@ -850,7 +850,7 @@ namespace Duplicati.Library.AutoUpdater { string optstr = Environment.GetEnvironmentVariable(string.Format(UPDATE_STRATEGY_ENVNAME_TEMPLATE, APPNAME)); AutoUpdateStrategy strategy; - if (string.IsNullOrWhiteSpace(optstr) || !Enum.TryParse(optstr, out strategy)) + if (string.IsNullOrWhiteSpace(optstr) || !Enum.TryParse(optstr, true, out strategy)) strategy = defaultstrategy; System.Threading.Thread backgroundChecker = null; diff --git a/Duplicati/Library/Main/Operation/RepairHandler.cs b/Duplicati/Library/Main/Operation/RepairHandler.cs index b189c79ea..eeb949ad7 100644 --- a/Duplicati/Library/Main/Operation/RepairHandler.cs +++ b/Duplicati/Library/Main/Operation/RepairHandler.cs @@ -309,138 +309,134 @@ namespace Duplicati.Library.Main.Operation } else if (n.Type == RemoteVolumeType.Index) { - using (IndexVolumeWriter w = new IndexVolumeWriter(m_options)) + IndexVolumeWriter w = new IndexVolumeWriter(m_options); + newEntry = w; + w.SetRemoteFilename(n.Name); + + var h = Library.Utility.HashAlgorithmHelper.Create(m_options.BlockHashAlgorithm); + + foreach (var blockvolume in db.GetBlockVolumesFromIndexName(n.Name)) { - newEntry = w; - w.SetRemoteFilename(n.Name); + w.StartVolume(blockvolume.Name); + var volumeid = db.GetRemoteVolumeID(blockvolume.Name); - var h = Library.Utility.HashAlgorithmHelper.Create(m_options.BlockHashAlgorithm); + foreach (var b in db.GetBlocks(volumeid)) + w.AddBlock(b.Hash, b.Size); - foreach (var blockvolume in db.GetBlockVolumesFromIndexName(n.Name)) - { - w.StartVolume(blockvolume.Name); - var volumeid = db.GetRemoteVolumeID(blockvolume.Name); + w.FinishVolume(blockvolume.Hash, blockvolume.Size); - foreach (var b in db.GetBlocks(volumeid)) - w.AddBlock(b.Hash, b.Size); + if (m_options.IndexfilePolicy == Options.IndexFileStrategy.Full) + foreach (var b in db.GetBlocklists(volumeid, m_options.Blocksize, hashsize)) + { + var bh = Convert.ToBase64String(h.ComputeHash(b.Item2, 0, b.Item3)); + if (bh != b.Item1) + throw new Exception(string.Format("Internal consistency check failed, generated index block has wrong hash, {0} vs {1}", bh, b.Item1)); - w.FinishVolume(blockvolume.Hash, blockvolume.Size); + w.WriteBlocklist(b.Item1, b.Item2, 0, b.Item3); + } + } - if (m_options.IndexfilePolicy == Options.IndexFileStrategy.Full) - foreach (var b in db.GetBlocklists(volumeid, m_options.Blocksize, hashsize)) - { - var bh = Convert.ToBase64String(h.ComputeHash(b.Item2, 0, b.Item3)); - if (bh != b.Item1) - throw new Exception(string.Format("Internal consistency check failed, generated index block has wrong hash, {0} vs {1}", bh, b.Item1)); + w.Close(); - w.WriteBlocklist(b.Item1, b.Item2, 0, b.Item3); - } - } - - w.Close(); - - if (m_options.Dryrun) - Logging.Log.WriteDryrunMessage(LOGTAG, "WouldReUploadIndexFile", "would re-upload index file {0}, with size {1}, previous size {2}", n.Name, Library.Utility.Utility.FormatSizeString(new System.IO.FileInfo(w.LocalFilename).Length), Library.Utility.Utility.FormatSizeString(n.Size)); - else - { - db.UpdateRemoteVolume(w.RemoteFilename, RemoteVolumeState.Uploading, -1, null, null); - backend.Put(w); - } + if (m_options.Dryrun) + Logging.Log.WriteDryrunMessage(LOGTAG, "WouldReUploadIndexFile", "would re-upload index file {0}, with size {1}, previous size {2}", n.Name, Library.Utility.Utility.FormatSizeString(new System.IO.FileInfo(w.LocalFilename).Length), Library.Utility.Utility.FormatSizeString(n.Size)); + else + { + db.UpdateRemoteVolume(w.RemoteFilename, RemoteVolumeState.Uploading, -1, null, null); + backend.Put(w); } } else if (n.Type == RemoteVolumeType.Blocks) { - using (BlockVolumeWriter w = new BlockVolumeWriter(m_options)) + BlockVolumeWriter w = new BlockVolumeWriter(m_options); + newEntry = w; + w.SetRemoteFilename(n.Name); + + using (var mbl = db.CreateBlockList(n.Name)) { - newEntry = w; - w.SetRemoteFilename(n.Name); - - using (var mbl = db.CreateBlockList(n.Name)) + //First we grab all known blocks from local files + foreach (var block in mbl.GetSourceFilesWithBlocks(m_options.Blocksize)) { - //First we grab all known blocks from local files - foreach (var block in mbl.GetSourceFilesWithBlocks(m_options.Blocksize)) + var hash = block.Hash; + var size = (int) block.Size; + + foreach (var source in block.Sources) { - var hash = block.Hash; - var size = (int) block.Size; + var file = source.File; + var offset = source.Offset; - foreach (var source in block.Sources) - { - var file = source.File; - var offset = source.Offset; - - try - { - if (System.IO.File.Exists(file)) - using (var f = System.IO.File.OpenRead(file)) - { - f.Position = offset; - if (size == Library.Utility.Utility.ForceStreamRead(f, buffer, size)) - { - var newhash = Convert.ToBase64String(blockhasher.ComputeHash(buffer, 0, size)); - if (newhash == hash) - { - if (mbl.SetBlockRestored(hash, size)) - w.AddBlock(hash, buffer, 0, size, Duplicati.Library.Interface.CompressionHint.Default); - break; - } - } - } - } - catch (Exception ex) - { - Logging.Log.WriteErrorMessage(LOGTAG, "FileAccessError", ex, "Failed to access file: {0}", file); - } - } - } - - //Then we grab all remote volumes that have the missing blocks - foreach (var vol in new AsyncDownloader(mbl.GetMissingBlockSources().ToList(), backend)) - { try { - using (var tmpfile = vol.TempFile) - using (var f = new BlockVolumeReader(RestoreHandler.GetCompressionModule(vol.Name), tmpfile, m_options)) - foreach (var b in f.Blocks) - if (mbl.SetBlockRestored(b.Key, b.Value)) - if (f.ReadBlock(b.Key, buffer) == b.Value) - w.AddBlock(b.Key, buffer, 0, (int) b.Value, Duplicati.Library.Interface.CompressionHint.Default); + if (System.IO.File.Exists(file)) + using (var f = System.IO.File.OpenRead(file)) + { + f.Position = offset; + if (size == Library.Utility.Utility.ForceStreamRead(f, buffer, size)) + { + var newhash = Convert.ToBase64String(blockhasher.ComputeHash(buffer, 0, size)); + if (newhash == hash) + { + if (mbl.SetBlockRestored(hash, size)) + w.AddBlock(hash, buffer, 0, size, Duplicati.Library.Interface.CompressionHint.Default); + break; + } + } + } } catch (Exception ex) { - Logging.Log.WriteErrorMessage(LOGTAG, "RemoteFileAccessError", ex, "Failed to access remote file: {0}", vol.Name); + Logging.Log.WriteErrorMessage(LOGTAG, "FileAccessError", ex, "Failed to access file: {0}", file); } } + } - // If we managed to recover all blocks, NICE! - var missingBlocks = mbl.GetMissingBlocks().Count(); - if (missingBlocks > 0) + //Then we grab all remote volumes that have the missing blocks + foreach (var vol in new AsyncDownloader(mbl.GetMissingBlockSources().ToList(), backend)) + { + try { - Logging.Log.WriteInformationMessage(LOGTAG, "RepairMissingBlocks", "Repair cannot acquire {0} required blocks for volume {1}, which are required by the following filesets: ", missingBlocks, n.Name); - foreach (var f in mbl.GetFilesetsUsingMissingBlocks()) - Logging.Log.WriteInformationMessage(LOGTAG, "AffectedFilesetName", f.Name); + using (var tmpfile = vol.TempFile) + using (var f = new BlockVolumeReader(RestoreHandler.GetCompressionModule(vol.Name), tmpfile, m_options)) + foreach (var b in f.Blocks) + if (mbl.SetBlockRestored(b.Key, b.Value)) + if (f.ReadBlock(b.Key, buffer) == b.Value) + w.AddBlock(b.Key, buffer, 0, (int) b.Value, Duplicati.Library.Interface.CompressionHint.Default); + } + catch (Exception ex) + { + Logging.Log.WriteErrorMessage(LOGTAG, "RemoteFileAccessError", ex, "Failed to access remote file: {0}", vol.Name); + } + } - var recoverymsg = string.Format("If you want to continue working with the database, you can use the \"{0}\" and \"{1}\" commands to purge the missing data from the database and the remote storage.", "list-broken-files", "purge-broken-files"); + // If we managed to recover all blocks, NICE! + var missingBlocks = mbl.GetMissingBlocks().Count(); + if (missingBlocks > 0) + { + Logging.Log.WriteInformationMessage(LOGTAG, "RepairMissingBlocks", "Repair cannot acquire {0} required blocks for volume {1}, which are required by the following filesets: ", missingBlocks, n.Name); + foreach (var f in mbl.GetFilesetsUsingMissingBlocks()) + Logging.Log.WriteInformationMessage(LOGTAG, "AffectedFilesetName", f.Name); - if (!m_options.Dryrun) - { - Logging.Log.WriteInformationMessage(LOGTAG, "RecoverySuggestion", "This may be fixed by deleting the filesets and running repair again"); + var recoverymsg = string.Format("If you want to continue working with the database, you can use the \"{0}\" and \"{1}\" commands to purge the missing data from the database and the remote storage.", "list-broken-files", "purge-broken-files"); - throw new UserInformationException(string.Format("Repair not possible, missing {0} blocks.\n" + recoverymsg, missingBlocks), "RepairIsNotPossible"); - } - else - { - Logging.Log.WriteInformationMessage(LOGTAG, "RecoverySuggestion", recoverymsg); - } + if (!m_options.Dryrun) + { + Logging.Log.WriteInformationMessage(LOGTAG, "RecoverySuggestion", "This may be fixed by deleting the filesets and running repair again"); + + throw new UserInformationException(string.Format("Repair not possible, missing {0} blocks.\n" + recoverymsg, missingBlocks), "RepairIsNotPossible"); } else { - if (m_options.Dryrun) - Logging.Log.WriteDryrunMessage(LOGTAG, "WouldReUploadBlockFile", "would re-upload block file {0}, with size {1}, previous size {2}", n.Name, Library.Utility.Utility.FormatSizeString(new System.IO.FileInfo(w.LocalFilename).Length), Library.Utility.Utility.FormatSizeString(n.Size)); - else - { - db.UpdateRemoteVolume(w.RemoteFilename, RemoteVolumeState.Uploading, -1, null, null); - backend.Put(w); - } + Logging.Log.WriteInformationMessage(LOGTAG, "RecoverySuggestion", recoverymsg); + } + } + else + { + if (m_options.Dryrun) + Logging.Log.WriteDryrunMessage(LOGTAG, "WouldReUploadBlockFile", "would re-upload block file {0}, with size {1}, previous size {2}", n.Name, Library.Utility.Utility.FormatSizeString(new System.IO.FileInfo(w.LocalFilename).Length), Library.Utility.Utility.FormatSizeString(n.Size)); + else + { + db.UpdateRemoteVolume(w.RemoteFilename, RemoteVolumeState.Uploading, -1, null, null); + backend.Put(w); } } } diff --git a/Duplicati/Library/UsageReporter/Reporter.cs b/Duplicati/Library/UsageReporter/Reporter.cs index d11036ac9..b4e568c02 100644 --- a/Duplicati/Library/UsageReporter/Reporter.cs +++ b/Duplicati/Library/UsageReporter/Reporter.cs @@ -173,7 +173,7 @@ namespace Duplicati.Library.UsageReporter { var str = Environment.GetEnvironmentVariable(string.Format(DISABLED_ENVNAME_TEMPLATE, AutoUpdater.AutoUpdateSettings.AppName)); ReportType tmp; - if (string.IsNullOrWhiteSpace(str) || !Enum.TryParse(str, out tmp)) + if (string.IsNullOrWhiteSpace(str) || !Enum.TryParse(str, true, out tmp)) Cached_MaxReportLevel = ReportType.Information; else Cached_MaxReportLevel = tmp; diff --git a/Duplicati/UnitTest/Duplicati.UnitTest.csproj b/Duplicati/UnitTest/Duplicati.UnitTest.csproj index 02ce5464f..6d7899dc7 100644 --- a/Duplicati/UnitTest/Duplicati.UnitTest.csproj +++ b/Duplicati/UnitTest/Duplicati.UnitTest.csproj @@ -204,4 +204,4 @@ - \ No newline at end of file + diff --git a/Duplicati/UnitTest/RepairHandlerTests.cs b/Duplicati/UnitTest/RepairHandlerTests.cs new file mode 100644 index 000000000..7c27bbee0 --- /dev/null +++ b/Duplicati/UnitTest/RepairHandlerTests.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Duplicati.Library.Main; +using NUnit.Framework; + +namespace Duplicati.UnitTest +{ + [TestFixture] + public class RepairHandlerTests : BasicSetupHelper + { + public override void SetUp() + { + base.SetUp(); + File.WriteAllBytes(Path.Combine(this.DATAFOLDER, "file"), new byte[] {0}); + } + + [Test] + [Category("RepairHandler")] + [TestCase("true")] + [TestCase("false")] + public void RepairMissingIndexFiles(string noEncryption) + { + Dictionary options = new Dictionary(this.TestOptions) {["no-encryption"] = noEncryption}; + using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) + { + c.Backup(new[] {this.DATAFOLDER}); + } + + string[] dindexFiles = Directory.EnumerateFiles(this.TARGETFOLDER, "*dindex*").ToArray(); + Assert.Greater(dindexFiles.Length, 0); + foreach (string f in dindexFiles) + { + File.Delete(f); + } + + using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) + { + c.Repair(); + } + + foreach (string file in dindexFiles) + { + Assert.IsTrue(File.Exists(Path.Combine(this.TARGETFOLDER, file))); + } + } + } +} \ No newline at end of file diff --git a/Installer/fedora/Dockerfile.build b/Installer/fedora/Dockerfile.build index c14e576e7..556fb0d4e 100644 --- a/Installer/fedora/Dockerfile.build +++ b/Installer/fedora/Dockerfile.build @@ -9,6 +9,12 @@ RUN dnf -y install deltarpm RUN dnf -y upgrade RUN dnf -y --allowerasing install @"Minimal Install" @buildsys-build yum-utils rpm-sign gnupg rpmdevtools +# Install real mono for building +# Instructions from here: https://www.mono-project.com/download/stable/#download-lin-fedora +RUN rpm --import "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF" +RUN curl https://download.mono-project.com/repo/centos8-stable.repo | tee /etc/yum.repos.d/mono-centos8-stable.repo +RUN dnf -y update + # Install mono things RUN dnf -y install mono-devel gnome-sharp-devel dos2unix git nuget diff --git a/build-installers.sh b/build-installers.sh index 508c404c0..6d3459e3b 100755 --- a/build-installers.sh +++ b/build-installers.sh @@ -26,6 +26,9 @@ MONO=/Library/Frameworks/Mono.framework/Commands/mono GPG=/usr/local/bin/gpg2 +# Newer GPG needs this to allow input from a non-terminal +export GPG_TTY=$(tty) + ZIPFILE=$(basename "$1") VERSION=$(echo "${ZIPFILE}" | cut -d "-" -f 2 | cut -d "_" -f 1) BUILDTYPE=$(echo "${ZIPFILE}" | cut -d "-" -f 2 | cut -d "_" -f 2) @@ -52,9 +55,18 @@ echo "DEBName: ${DEBNAME}" echo "SPKName: ${SPKNAME}" build_file_signatures() { - if [ "z${GPGID}" != "z" ]; then - echo "$GPGKEY" | "${GPG}" "--passphrase-fd" "0" "--batch" "--yes" "--default-key=${GPGID}" "--output" "$2.sig" "--detach-sig" "$1" - echo "$GPGKEY" | "${GPG}" "--passphrase-fd" "0" "--batch" "--yes" "--default-key=${GPGID}" "--armor" "--output" "$2.sig.asc" "--detach-sig" "$1" + if [ -f "${GPG_KEYFILE}" ]; then + "${MONO}" "BuildTools/GnupgSigningTool/bin/Debug/GnupgSigningTool.exe" \ + --inputfile=\"$1\" \ + --signaturefile=\"$2.sig\" \ + --armor=false --gpgkeyfile="${GPG_KEYFILE}" --gpgpath="${GPG}" \ + --keyfile-password="${KEYFILE_PASSWORD}" + + "${MONO}" "BuildTools/GnupgSigningTool/bin/Debug/GnupgSigningTool.exe" \ + --inputfile=\"$1\" \ + --signaturefile=\"$2.sig.asc\" \ + --armor=true --gpgkeyfile="${GPG_KEYFILE}" --gpgpath="${GPG}" \ + --keyfile-password="${KEYFILE_PASSWORD}" fi md5 "$1" | awk -F ' ' '{print $NF}' > "$2.md5" diff --git a/build-release.sh b/build-release.sh index 75d164947..a747b8c51 100644 --- a/build-release.sh +++ b/build-release.sh @@ -33,6 +33,8 @@ XBUILD=/Library/Frameworks/Mono.framework/Commands/msbuild NUGET=/Library/Frameworks/Mono.framework/Commands/nuget MONO=/Library/Frameworks/Mono.framework/Commands/mono GPG=/usr/local/bin/gpg2 +AWS=/usr/local/bin/aws +GITHUB_RELEASE=/usr/local/bin/github-release # Newer GPG needs this to allow input from a non-terminal export GPG_TTY=$(tty) @@ -57,6 +59,18 @@ if [ ! -f "$NUGET" ]; then exit 1 fi +if [ ! -f "$AWS" ]; then + echo "aws-cli not found: $AWS" + exit 1 +fi + +if [ ! -f "$GITHUB_RELEASE" ]; then + echo "github-release executable not found: $GITHUB_RELEASE" + echo "Grab it from: https://github.com/aktau/github-release" + exit 1 +fi + + # The "OTHER_UPLOADS" setting is no longer used if [ "${RELEASE_TYPE}" == "nightly" ]; then OTHER_UPLOADS="" @@ -281,12 +295,12 @@ cp "${UPDATE_TARGET}/latest.zip.sig.asc" "${UPDATE_TARGET}/${RELEASE_FILE_NAME}. "${MONO}" "BuildTools/UpdateVersionStamp/bin/Debug/UpdateVersionStamp.exe" --version="2.0.0.7" echo "Uploading binaries" -aws --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip" -aws --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip.sig" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip.sig" -aws --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip.sig.asc" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip.sig.asc" -aws --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.manifest" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.manifest" +"${AWS}" --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip" +"${AWS}" --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip.sig" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip.sig" +"${AWS}" --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip.sig.asc" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.zip.sig.asc" +"${AWS}" --profile=duplicati-upload s3 cp "${UPDATE_TARGET}/${RELEASE_FILE_NAME}.manifest" "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.manifest" -aws --profile=duplicati-upload s3 cp "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.manifest" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.manifest" +"${AWS}" --profile=duplicati-upload s3 cp "s3://updates.duplicati.com/${RELEASE_TYPE}/${RELEASE_FILE_NAME}.manifest" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.manifest" ZIP_MD5=$(md5 ${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip | awk -F ' ' '{print $NF}') ZIP_SHA1=$(shasum -a 1 ${UPDATE_TARGET}/${RELEASE_FILE_NAME}.zip | awk -F ' ' '{print $1}') @@ -311,8 +325,8 @@ echo "duplicati_version_info =" > "latest.js" cat "latest.json" >> "latest.js" echo ";" >> "latest.js" -aws --profile=duplicati-upload s3 cp "latest.json" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.json" -aws --profile=duplicati-upload s3 cp "latest.js" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.js" +"${AWS}" --profile=duplicati-upload s3 cp "latest.json" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.json" +"${AWS}" --profile=duplicati-upload s3 cp "latest.js" "s3://updates.duplicati.com/${RELEASE_TYPE}/latest.js" # echo "Propagating to other build types" # for OTHER in ${OTHER_UPLOADS}; do @@ -338,14 +352,12 @@ fi RELEASE_MESSAGE=$(printf "Changes in this version:\n${RELEASE_CHANGEINFO_NEWS}") -# Using the tool from https://github.com/aktau/github-release - GITHUB_TOKEN=$(cat "${GITHUB_TOKEN_FILE}") if [ "x${GITHUB_TOKEN}" == "x" ]; then echo "No GITHUB_TOKEN found in environment, you can manually upload the binaries" else - github-release release ${PRE_RELEASE_LABEL} \ + "${GITHUB_RELEASE}" release ${PRE_RELEASE_LABEL} \ --tag "v${RELEASE_VERSION}-${RELEASE_NAME}" \ --name "v${RELEASE_VERSION}-${RELEASE_NAME}" \ --repo "duplicati" \ @@ -353,7 +365,7 @@ else --security-token "${GITHUB_TOKEN}" \ --description "${RELEASE_MESSAGE}" \ - github-release upload \ + "${GITHUB_RELEASE}" upload \ --tag "v${RELEASE_VERSION}-${RELEASE_NAME}" \ --name "${RELEASE_FILE_NAME}.zip" \ --repo "duplicati" \ diff --git a/pipeline/start.sh b/pipeline/start.sh index 801148791..d052abd94 100755 --- a/pipeline/start.sh +++ b/pipeline/start.sh @@ -8,5 +8,5 @@ ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories BulkNormal ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories BulkNoSize ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories SVNDataLong,SVNData,RecoveryTool ${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories Border -${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories Filter,Targeted,Purge,Serialization,WebApi,Utility,UriUtility,IO,ImportExport,Disruption,RestoreHandler +${ROOT_DIR}/pipeline/jobs/unittest_job.sh --testcategories Filter,Targeted,Purge,Serialization,WebApi,Utility,UriUtility,IO,ImportExport,Disruption,RestoreHandler,RepairHandler