diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index cdbfc23cd..26d455b8f 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -10,43 +10,28 @@ on: required: false env: - JAVA_VERSION: 17 + JAVA_VERSION: 19 jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ github.event.inputs.version }} + build: name: Build AppImage runs-on: ubuntu-latest + needs: [get-version] steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 + - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} cache: 'maven' - - id: versions - name: Apply version information - run: | - if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR=${GITHUB_REF##*/} - mvn versions:set -DnewVersion=${SEM_VER_STR} - elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR="${{ github.event.inputs.version }}" - mvn versions:set -DnewVersion=${SEM_VER_STR} - else - SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` - fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` - REVCOUNT=`git rev-list --count HEAD` - echo "::set-output name=semVerStr::${SEM_VER_STR}" - echo "::set-output name=semVerNum::${SEM_VER_NUM}" - echo "::set-output name=revNum::${REVCOUNT}" - - name: Validate Version - uses: skymatic/semver-validation-action@v1 - with: - version: ${{ steps.versions.outputs.semVerStr }} + - name: Set version + run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} - name: Run maven run: mvn -B clean package -Pdependency-check,linux -DskipTests - name: Patch target dir @@ -60,7 +45,7 @@ jobs: --verbose --output runtime --module-path "${JAVA_HOME}/jmods" - --add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr + --add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr --strip-native-commands --no-header-files --no-man-pages @@ -69,8 +54,8 @@ jobs: - name: Prepare additional launcher run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties env: - SEMVER_STR: ${{ steps.versions.outputs.semVerStr }} - REVISION_NUM: ${{ steps.versions.outputs.revNum }} + SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }} + REVISION_NUM: ${{ needs.get-version.outputs.revNum }} - name: Run jpackage run: > ${JAVA_HOME}/bin/jpackage @@ -84,18 +69,19 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2022 Skymatic GmbH" - --app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}" + --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}" --java-options "-Xss5m" --java-options "-Xmx256m" - --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" --java-options "-Dfile.encoding=\"utf-8\"" --java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" --java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" --java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" + --java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\"" --java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" --java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" --java-options "-Dcryptomator.showTrayIcon=false" - --java-options "-Dcryptomator.buildNumber=\"appimage-${{ steps.versions.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.get-version.outputs.revNum }}\"" --add-launcher Cryptomator-gtk2=launcher-gtk2.properties --resource-dir dist/linux/resources - name: Patch Cryptomator.AppDir @@ -133,7 +119,7 @@ jobs: GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - name: Build AppImage run: > - ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ steps.versions.outputs.semVerStr }}-x86_64.AppImage + ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-x86_64.AppImage -u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync' --sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback" - name: Create detached GPG signatures diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5270365b3..d94048ee9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,26 +6,25 @@ on: types: [labeled] env: - JAVA_VERSION: 17 + JAVA_VERSION: 19 defaults: run: shell: bash -jobs: +jobs: test: name: Compile and Test runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} cache: 'maven' - name: Cache SonarCloud packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml index fb8b3a423..a194d4ad1 100644 --- a/.github/workflows/debian.yml +++ b/.github/workflows/debian.yml @@ -15,48 +15,37 @@ on: required: false env: - JAVA_VERSION: 17 + JAVA_VERSION: 19 jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ github.event.inputs.version }} + build: name: Build Debian Package - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 + needs: [get-version] steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 + - uses: actions/checkout@v3 - name: Install build tools run: | + sudo add-apt-repository ppa:coffeelibs/openjdk sudo apt-get update - sudo apt-get install debhelper devscripts dput + sudo apt-get install debhelper devscripts dput coffeelibs-jdk-19 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} cache: 'maven' - - id: versions - name: Apply version information - run: | - if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR=${GITHUB_REF##*/} - mvn versions:set -DnewVersion=${SEM_VER_STR} - elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR="${{ github.event.inputs.version }}" - mvn versions:set -DnewVersion=${SEM_VER_STR} - else - SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` - fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` - REVCOUNT=`git rev-list --count HEAD` - echo "::set-output name=semVerStr::${SEM_VER_STR}" - echo "::set-output name=semVerNum::${SEM_VER_NUM}" - echo "::set-output name=revNum::${REVCOUNT}" - echo "::set-output name=ppaVerStr::${SEM_VER_STR/-/\~}-${REVCOUNT}" - - name: Validate Version - uses: skymatic/semver-validation-action@v1 - with: - version: ${{ steps.versions.outputs.semVerStr }} + - id: versions + name: Create PPA version string + run: echo "ppaVerStr=${SEM_VER_STR/-/\~}-${REVCOUNT}" >> $GITHUB_OUTPUT + env: + SEM_VER_STR: ${{ needs.get-version.outputs.semVerStr }} + REVCOUNT: ${{ needs.get-version.outputs.revNum }} - name: Run maven run: mvn -B clean package -Pdependency-check,linux -DskipTests - name: Create orig.tar.gz with common/ libs/ mods/ @@ -76,9 +65,9 @@ jobs: find . -name "*.jar" >> pkgdir/debian/source/include-binaries mv pkgdir cryptomator_${{ steps.versions.outputs.ppaVerStr }} env: - SEMVER_STR: ${{ steps.versions.outputs.semVerStr }} - VERSION_NUM: ${{ steps.versions.outputs.semVerNum }} - REVISION_NUM: ${{ steps.versions.outputs.revNum }} + SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }} + VERSION_NUM: ${{ needs.get-version.outputs.semVerNum }} + REVISION_NUM: ${{ needs.get-version.outputs.revNum }} PPA_VERSION: ${{ steps.versions.outputs.ppaVerStr }}-0ppa1 - name: Prepare GPG-Agent for signing with key 615D449FE6E6A235 run: | @@ -111,7 +100,7 @@ jobs: cryptomator_*_amd64.deb cryptomator_*.asc - name: Publish on PPA - if: startsWith(github.ref, 'refs/tags/') || github.event.inputs.dput == 'true' + if: startsWith(github.ref, 'refs/tags/') || inputs.dput run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes - name: Publish Debian package on GitHub Releases if: startsWith(github.ref, 'refs/tags/') diff --git a/.github/workflows/dl-stats.yml b/.github/workflows/dl-stats.yml new file mode 100644 index 000000000..dc87a2bbd --- /dev/null +++ b/.github/workflows/dl-stats.yml @@ -0,0 +1,63 @@ +name: Report Download Stats + +on: + schedule: + - cron: '0/15 * * * *' # run every 15 min - don't forget to adjust the "interval" in the json sent to the metrics endpoint + +jobs: + report-download-stats: + runs-on: ubuntu-latest + steps: + - name: Get download count of latest releases + id: get-stats + uses: actions/github-script@v6 + with: + script: | + const query = `query($owner:String!, $name:String!) { + repository(owner:$owner, name:$name){ + releases(first: 10, orderBy: {field: CREATED_AT, direction: DESC}) { + nodes { + isPrerelease + tagName + releaseAssets(first: 20) { + nodes { + name + downloadCount + } + } + } + } + } + }`; + const variables = { + owner: context.repo.owner, + name: context.repo.repo + } + return await github.graphql(query, variables) + - name: Transform Results + id: transform-stats + run: | + TIME=$(($(date +%s) / $INTERVAL * $INTERVAL)) + echo ${JSON_DATA} | jq --arg TIME "$TIME" --arg INTERVAL "$INTERVAL" -c '.repository.releases.nodes[] | select(.isPrerelease == false) | .tagName as $tagName | .releaseAssets.nodes[] | {filename: .name, downloads: .downloadCount, release: $tagName, time: ($TIME|tonumber), interval: ($INTERVAL|tonumber)}' > input.json + + jq -c 'select(.filename|endswith("-x86_64.AppImage")) | {name: "github.releases.downloads", tags: ["file=AppImage", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + jq -c 'select(.filename|endswith("_amd64.deb")) | {name: "github.releases.downloads", tags: ["file=deb", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + jq -c 'select(.filename|endswith("-x64.msi")) | {name: "github.releases.downloads", tags: ["file=msi", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + jq -c 'select(.filename|endswith("-x64.exe")) | {name: "github.releases.downloads", tags: ["file=exe", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + jq -c 'select(.filename|endswith("-arm64.dmg")) | {name: "github.releases.downloads", tags: ["file=dmg", "version=\(.release)", "arch=arm64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + jq -c 'select(.filename|endswith(".dmg")) | select(.filename|endswith("-arm64.dmg")|not) | {name: "github.releases.downloads", tags: ["file=dmg", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json + + RESULT=$(jq -s -c "." output.json) + echo "result=${RESULT}" >> $GITHUB_OUTPUT + env: + INTERVAL: 900 + JSON_DATA: ${{ steps.get-stats.outputs.result }} + - name: Upload Results + uses: fjogeleit/http-request-action@v1 + with: + url: 'https://graphite-us-central1.grafana.net/metrics' + method: 'POST' + contentType: 'application/json' + bearerToken: ${{ secrets.GRAFANA_GRAPHITE_TOKEN }} + data: ${{ steps.transform-stats.outputs.result }} + continue-on-error: true # currently there seems to be a problem with the metrics endpoint, failing every now and then diff --git a/.github/workflows/error-db.yml b/.github/workflows/error-db.yml new file mode 100644 index 000000000..09a15fe1f --- /dev/null +++ b/.github/workflows/error-db.yml @@ -0,0 +1,60 @@ +name: Update Error Database + +on: + discussion: + types: [created, edited, category_changed, answered, unanswered] + discussion_comment: + types: [created, edited, deleted] + +jobs: + update-error-db: + runs-on: ubuntu-latest + if: github.event.discussion.category.name == 'Errors' + steps: + - name: Query Discussion Data + id: query-data + uses: actions/github-script@v6 + with: + script: | + const query = `query ($owner: String!, $name: String!, $discussionNumber: Int!) { + repository(owner: $owner, name: $name) { + discussion(number: $discussionNumber) { + id + upvoteCount + title + url + answer { + url + upvoteCount + } + comments { + totalCount + } + } + } + }`; + const variables = { + owner: context.repo.owner, + name: context.repo.repo, + discussionNumber: context.payload.discussion.number + } + return await github.graphql(query, variables) + - name: Get Gist + id: get-gist + uses: andymckay/get-gist-action@master + with: + gistURL: https://gist.github.com/cryptobot/accba9fb9555e7192271b85606f97230 + - name: Merge Error Code Data + run: | + jq -c '.' ${{ steps.get-gist.outputs.file }} > original.json + echo $DISCUSSION | jq -c '.repository.discussion | .comments = .comments.totalCount | {(.id|tostring) : .}' > new.json + jq -s '.[0] * .[1]' original.json new.json > merged.json + env: + DISCUSSION: ${{ steps.query-data.outputs.result }} + - name: Patch Gist + uses: exuanbo/actions-deploy-gist@v1 + with: + token: ${{ secrets.CRYPTOBOT_GIST_TOKEN }} + gist_id: accba9fb9555e7192271b85606f97230 + gist_file_name: errorcodes.json + file_path: merged.json diff --git a/.github/workflows/get-version.yml b/.github/workflows/get-version.yml new file mode 100644 index 000000000..e6131b835 --- /dev/null +++ b/.github/workflows/get-version.yml @@ -0,0 +1,77 @@ +name: Parse and Validate a version string or tag + +on: + workflow_call: + inputs: + version: + description: "A specific version to use" + required: false + type: string + outputs: + semVerStr: + description: "The full version string." + value: ${{ jobs.determine-version.outputs.semVerStr}} + semVerNum: + description: "The numerical part of the version string" + value: ${{ jobs.determine-version.outputs.semVerNum}} + revNum: + description: "The revision number" + value: ${{ jobs.determine-version.outputs.revNum}} + versionType: + description: "Type of the version. Values are [stable, alpha, beta, rc, unknown]" + value: ${{ jobs.determine-version.outputs.type }} + +env: + JAVA_VERSION: 19 + JAVA_DIST: 'temurin' + JAVA_CACHE: 'maven' + +jobs: + determine-version: + name: 'Determines the version following semver' + runs-on: ubuntu-latest + outputs: + semVerNum: ${{ steps.versions.outputs.semVerNum }} + semVerStr: ${{ steps.versions.outputs.semVerStr }} + revNum: ${{ steps.versions.outputs.revNum }} + type: ${{ steps.versions.outputs.type}} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Java + uses: actions/setup-java@v3 + with: + distribution: ${{ env.JAVA_DIST }} + java-version: ${{ env.JAVA_VERSION }} + cache: ${{ env.JAVA_CACHE }} + - id: versions + name: Get version information + run: | + if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + elif [[ "${{ inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR="${{ github.event.inputs.version }}" + else + SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` + fi + SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + REVCOUNT=`git rev-list --count HEAD` + TYPE="unknown" + if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then + TYPE="stable" + elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9] ]]; then + TYPE="alpha" + elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9] ]]; then + TYPE="beta" + elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9] ]]; then + TYPE="rc" + fi + echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT + echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT + echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT + echo "type=${TYPE}" >> $GITHUB_OUTPUT + - name: Validate Version + uses: skymatic/semver-validation-action@v2 + with: + version: ${{ steps.versions.outputs.semVerStr }} \ No newline at end of file diff --git a/.github/workflows/mac-dmg.yml b/.github/workflows/mac-dmg.yml index 833acac61..4f06953be 100644 --- a/.github/workflows/mac-dmg.yml +++ b/.github/workflows/mac-dmg.yml @@ -10,43 +10,41 @@ on: required: false env: - JAVA_VERSION: 17 + JAVA_VERSION: 19 jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ github.event.inputs.version }} + build: - name: Build Cryptomator.app - runs-on: macos-11 + name: Build Cryptomator.app for ${{ matrix.output-suffix }} + runs-on: ${{ matrix.os }} + needs: [get-version] + strategy: + fail-fast: false + matrix: + include: + - os: macos-11 + architecture: x64 + output-suffix: x64 + xcode-path: '/Applications/Xcode_13.2.1.app' + - os: [self-hosted, macOS, ARM64] + architecture: aarch64 + output-suffix: arm64 + xcode-path: '/Applications/Xcode_13.2.1.app' steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 + - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + architecture: ${{ matrix.architecture }} cache: 'maven' - - id: versions - name: Apply version information - run: | - if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR=${GITHUB_REF##*/} - mvn versions:set -DnewVersion=${SEM_VER_STR} - elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR="${{ github.event.inputs.version }}" - mvn versions:set -DnewVersion=${SEM_VER_STR} - else - SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` - fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` - REVCOUNT=`git rev-list --count HEAD` - echo "::set-output name=semVerStr::${SEM_VER_STR}" - echo "::set-output name=semVerNum::${SEM_VER_NUM}" - echo "::set-output name=revNum::${REVCOUNT}" - - name: Validate Version - uses: skymatic/semver-validation-action@v1 - with: - version: ${{ steps.versions.outputs.semVerStr }} + - name: Set version + run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} - name: Run maven run: mvn -B clean package -Pdependency-check,mac -DskipTests - name: Patch target dir @@ -60,7 +58,7 @@ jobs: --verbose --output runtime --module-path "${JAVA_HOME}/jmods" - --add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr + --add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr --strip-native-commands --no-header-files --no-man-pages @@ -79,19 +77,21 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2022 Skymatic GmbH" - --app-version "${{ steps.versions.outputs.semVerNum }}" + --app-version "${{ needs.get-version.outputs.semVerNum }}" --java-options "-Xss5m" --java-options "-Xmx256m" --java-options "-Dfile.encoding=\"utf-8\"" --java-options "-Dapple.awt.enableTemplateImages=true" --java-options "-Dsun.java2d.metal=true" - --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" --java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\"" --java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\"" --java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\"" + --java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\"" --java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\"" + --java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\"" --java-options "-Dcryptomator.showTrayIcon=true" - --java-options "-Dcryptomator.buildNumber=\"dmg-${{ steps.versions.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\"" --mac-package-identifier org.cryptomator --resource-dir dist/mac/resources - name: Patch Cryptomator.app @@ -101,8 +101,8 @@ jobs: sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist env: - VERSION_NO: ${{ steps.versions.outputs.semVerNum }} - REVISION_NO: ${{ steps.versions.outputs.revNum }} + VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} + REVISION_NO: ${{ needs.get-version.outputs.revNum }} - name: Generate license for dmg run: > mvn -B license:add-third-party @@ -136,6 +136,10 @@ jobs: CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }} - name: Codesign run: | + echo "Codesigning jdk files..." + find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; + find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name 'jspawnhelper' -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \; + echo "Codesigning jar contents..." find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \; for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then @@ -184,38 +188,20 @@ jobs: --icon ".background" 128 758 --icon ".fseventsd" 320 758 --icon ".VolumeIcon.icns" 512 758 - Cryptomator-${VERSION_NO}.dmg dmg + Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg env: - VERSION_NO: ${{ steps.versions.outputs.semVerNum }} - - name: Install notarization credentials - if: startsWith(github.ref, 'refs/tags/') - run: | - # create temporary keychain - KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db - security create-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} - security set-keychain-settings -lut 900 ${KEYCHAIN_PATH} - security unlock-keychain -p "${NOTARIZATION_TMP_KEYCHAIN_PW}" ${KEYCHAIN_PATH} - - # import credentials from secrets - sudo xcode-select -s /Applications/Xcode_13.0.app - xcrun notarytool store-credentials "${NOTARIZATION_KEYCHAIN_PROFILE}" --apple-id "${NOTARIZATION_APPLE_ID}" --password "${NOTARIZATION_PW}" --team-id "${NOTARIZATION_TEAM_ID}" --keychain "${KEYCHAIN_PATH}" - env: - NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} - NOTARIZATION_APPLE_ID: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} - NOTARIZATION_PW: ${{ secrets.MACOS_NOTARIZATION_PW }} - NOTARIZATION_TEAM_ID: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} - NOTARIZATION_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_NOTARIZATION_TMP_KEYCHAIN_PW }} + VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} - name: Notarize .dmg if: startsWith(github.ref, 'refs/tags/') - run: | - KEYCHAIN_PATH=$RUNNER_TEMP/notarization.keychain-db - sudo xcode-select -s /Applications/Xcode_13.0.app - xcrun notarytool submit Cryptomator-*.dmg --keychain-profile "${NOTARIZATION_KEYCHAIN_PROFILE}" --keychain "${KEYCHAIN_PATH}" --wait - xcrun stapler staple Cryptomator-*.dmg - env: - NOTARIZATION_KEYCHAIN_PROFILE: ${{ secrets.MACOS_NOTARIZATION_KEYCHAIN_PROFILE }} + uses: cocoalibs/xcode-notarization-action@v1 + with: + app-path: 'Cryptomator-*.dmg' + apple-id: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }} + password: ${{ secrets.MACOS_NOTARIZATION_PW }} + team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} + xcode-path: ${{ matrix.xcode-path }} - name: Add possible alpha/beta tags to installer name - run: mv Cryptomator-*.dmg Cryptomator-${{ steps.versions.outputs.semVerStr }}.dmg + run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -227,14 +213,10 @@ jobs: if: ${{ always() }} run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db continue-on-error: true - - name: Clean up notarization credentials - if: ${{ always() }} - run: security delete-keychain $RUNNER_TEMP/notarization.keychain-db - continue-on-error: true - name: Upload artifacts uses: actions/upload-artifact@v3 with: - name: dmg + name: dmg-${{ matrix.output-suffix }} path: Cryptomator-*.dmg if-no-files-found: error - name: Publish dmg on GitHub Releases @@ -246,5 +228,3 @@ jobs: files: | Cryptomator-*.dmg Cryptomator-*.asc - - diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 79a0d5a21..48f7bd185 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -4,7 +4,7 @@ on: pull_request: env: - JAVA_VERSION: 17 + JAVA_VERSION: 19 defaults: run: @@ -16,10 +16,10 @@ jobs: runs-on: ubuntu-latest if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} cache: 'maven' - name: Build and Test diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml new file mode 100644 index 000000000..7309cb852 --- /dev/null +++ b/.github/workflows/release-check.yml @@ -0,0 +1,43 @@ +name: Release Check + +on: + push: + branches: + - 'release/**' + - 'hotfix/**' + +env: + JAVA_VERSION: 19 + +defaults: + run: + shell: bash + +jobs: + release-check-precondition: + name: Validate commits pushed to release/hotfix branch to fulfill release requirements + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - id: validate-pom-version + name: Validate POM version + run: | + if [[ $GITHUB_REF =~ refs/heads/(hotfix|release)/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then + SEM_VER_STR=${GITHUB_REF##*/} + else + echo "Failed to parse version" + exit 1 + fi + + if [[ ${SEM_VER_STR} == `mvn help:evaluate -Dexpression=project.version -q -DforceStdout` ]]; then + echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT + else + echo "Version not set in POM" + exit 1 + fi + - name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file + run: | + if ! grep -q "" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then + echo "Release not set in dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml" + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml index 3a9ed8ab0..0725c0329 100644 --- a/.github/workflows/win-exe.yml +++ b/.github/workflows/win-exe.yml @@ -10,48 +10,36 @@ on: required: false env: - JAVA_VERSION: 17 - WINFSP_MSI: https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi + JAVA_VERSION: 19 + JAVA_DIST: 'zulu' + JAVA_CACHE: 'maven' defaults: run: shell: bash jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ github.event.inputs.version }} + build-msi: name: Build .msi Installer runs-on: windows-latest + needs: [get-version] + env: + LOOPBACK_ALIAS: 'cryptomator-vault' steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 + - uses: actions/checkout@v3 - name: Setup Java - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: ${{ env.JAVA_DIST }} java-version: ${{ env.JAVA_VERSION }} - cache: 'maven' - - id: versions - name: Apply version information - run: | - if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR=${GITHUB_REF##*/} - mvn versions:set -DnewVersion=${SEM_VER_STR} - elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then - SEM_VER_STR="${{ github.event.inputs.version }}" - mvn versions:set -DnewVersion=${SEM_VER_STR} - else - SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` - fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` - REVCOUNT=`git rev-list --count HEAD` - echo "::set-output name=semVerStr::${SEM_VER_STR}" - echo "::set-output name=semVerNum::${SEM_VER_NUM}" - echo "::set-output name=revNum::${REVCOUNT}" - - name: Validate Version - uses: skymatic/semver-validation-action@v1 - with: - version: ${{ steps.versions.outputs.semVerStr }} + cache: ${{ env.JAVA_CACHE }} + - name: Set version + run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} - name: Run maven run: mvn -B clean package -Pdependency-check,win -DskipTests - name: Patch target dir @@ -65,7 +53,7 @@ jobs: --verbose --output runtime --module-path "${JAVA_HOME}/jmods" - --add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr + --add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr --strip-native-commands --no-header-files --no-man-pages @@ -84,33 +72,46 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2022 Skymatic GmbH" - --app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}" + --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}" --java-options "-Xss5m" --java-options "-Xmx256m" - --java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" --java-options "-Dfile.encoding=\"utf-8\"" --java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\"" --java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\"" --java-options "-Dcryptomator.settingsPath=\"~/AppData/Roaming/Cryptomator/settings.json\"" + --java-options "-Dcryptomator.p12Path=\"~/AppData/Roaming/Cryptomator/key.p12\"" --java-options "-Dcryptomator.ipcSocketPath=\"~/AppData/Roaming/Cryptomator/ipc.socket\"" - --java-options "-Dcryptomator.keychainPath=\"~/AppData/Roaming/Cryptomator/keychain.json\"" --java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\"" + --java-options "-Dcryptomator.loopbackAlias=\"${{ env.LOOPBACK_ALIAS }}\"" --java-options "-Dcryptomator.showTrayIcon=true" - --java-options "-Dcryptomator.buildNumber=\"msi-${{ steps.versions.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\"" + --java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\"" + --java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\"" --resource-dir dist/win/resources --icon dist/win/resources/Cryptomator.ico - name: Patch Application Directory run: | cp dist/win/contrib/* appdir/Cryptomator + - name: Set LOOPBACK_ALIAS in patchWebDAV.bat + shell: pwsh + run: | + $patchScript = "appdir\Cryptomator\patchWebDAV.bat" + try { + (Get-Content $patchScript ) -replace '::REPLACE ME', "SET LOOPBACK_ALIAS=`"${{ env.LOOPBACK_ALIAS}}`"" | Set-Content $patchScript + } catch { + Write-Host "Failed to set LOOPBACK_ALIAS for patchWebDAV.bat" + exit 1 + } - name: Fix permissions run: attrib -r appdir/Cryptomator/Cryptomator.exe shell: pwsh - name: Codesign - uses: skymatic/code-sign-action@v1 + uses: skymatic/code-sign-action@v2 with: certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A description: Cryptomator timestampUrl: 'http://timestamp.digicert.com' folder: appdir/Cryptomator @@ -137,7 +138,7 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2022 Skymatic GmbH" - --app-version "${{ steps.versions.outputs.semVerNum }}" + --app-version "${{ needs.get-version.outputs.semVerNum }}" --win-menu --win-dir-chooser --win-shortcut-prompt @@ -149,16 +150,16 @@ jobs: env: JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs - name: Codesign MSI - uses: skymatic/code-sign-action@v1 + uses: skymatic/code-sign-action@v2 with: certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A description: Cryptomator Installer timestampUrl: 'http://timestamp.digicert.com' folder: installer - name: Add possible alpha/beta tags to installer name - run: mv installer/Cryptomator-*.msi Cryptomator-${{ steps.versions.outputs.semVerStr }}-x64.msi + run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.msi - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -183,29 +184,34 @@ jobs: files: | *.msi *.asc - outputs: - semVerNum: ${{ steps.versions.outputs.semVerNum }} - semVerStr: ${{ steps.versions.outputs.semVerStr }} - revNum: ${{ steps.versions.outputs.revNum }} + + call-winget-flow: + needs: [get-version, build-msi] + if: github.event.action == 'published' && needs.get-version.outputs.type == 'stable' + uses: ./.github/workflows/winget.yml + with: + releaseTag: ${{ github.event.release.tag_name }} + secrets: inherit + build-exe: name: Build .exe installer runs-on: windows-latest - needs: [build-msi] + needs: [get-version, build-msi] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Download .msi - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: msi path: dist/win/bundle/resources - name: Strip version info from msi file name run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi - - uses: actions/setup-java@v2 + - uses: actions/setup-java@v3 with: - distribution: 'temurin' + distribution: ${{ env.JAVA_DIST }} java-version: ${{ env.JAVA_VERSION }} - cache: 'maven' + cache: ${{ env.JAVA_CACHE }} - name: Generate license for exe run: > mvn -B license:add-third-party @@ -218,14 +224,16 @@ jobs: "-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges" shell: pwsh - name: Download WinFsp - run: - curl --output dist/win/bundle/resources/winfsp.msi -L ${{ env.WINFSP_MSI }} + run: | + $winfspUrl= (Select-String -Path ".\dist\win\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value + curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl + shell: pwsh - name: Compile to wixObj file run: > "${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs -ext WixBalExtension -out dist/win/bundle/ - -dBundleVersion="${{ needs.build-msi.outputs.semVerNum }}.${{ needs.build-msi.outputs.revNum }}" + -dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}" -dBundleVendor="Skymatic GmbH" -dBundleCopyright="(C) 2016 - 2022 Skymatic GmbH" -dAboutUrl="https://cryptomator.org" @@ -242,11 +250,11 @@ jobs: -ib installer/unsigned/Cryptomator-Installer.exe -o tmp/engine.exe - name: Codesign burn engine - uses: skymatic/code-sign-action@v1 + uses: skymatic/code-sign-action@v2 with: certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A description: Cryptomator Installer timestampUrl: 'http://timestamp.digicert.com' folder: tmp @@ -256,16 +264,16 @@ jobs: -ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe -o installer/Cryptomator-Installer.exe - name: Codesign EXE - uses: skymatic/code-sign-action@v1 + uses: skymatic/code-sign-action@v2 with: certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }} password: ${{ secrets.WIN_CODESIGN_P12_PW }} - certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B + certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A description: Cryptomator Installer timestampUrl: 'http://timestamp.digicert.com' folder: installer - name: Add possible alpha/beta tags to installer name - run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.build-msi.outputs.semVerStr }}-x64.exe + run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.exe - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml new file mode 100644 index 000000000..7115a1785 --- /dev/null +++ b/.github/workflows/winget.yml @@ -0,0 +1,49 @@ +name: Release to Winget + +on: + workflow_call: + inputs: + releaseTag: + required: true + type: string + workflow_dispatch: + inputs: + releaseTag: + description: 'Release tag name' + required: true + type: string + +jobs: + publish-winget: + name: Publish on winget repo + runs-on: windows-latest + steps: + - name: Get download url for msi artifacts + id: get-release-assets + uses: actions/github-script@v6 + with: + script: | + const query =`query($tag:String!) { + repository(owner:"cryptomator", name:"cryptomator"){ + release(tagName: $tag) { + releaseAssets(first:20) { + nodes { + name + downloadUrl + } + } + } + } + }`; + const variables = { + tag: "${{ inputs.releaseTag }}" + } + return await github.graphql(query, variables) + - name: Submit package to Windows Package Manager Community Repository + id: submit-winget + run: | + iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe + $releaseAssets = (ConvertFrom-Json '${{ steps.get-release-assets.outputs.result }}').repository.release.releaseAssets.nodes + $installerUrl = $releaseAssets | Where-Object -Property name -match '^Cryptomator-.*\.msi$' | Select -ExpandProperty downloadUrl -First 1 + .\wingetcreate.exe update Cryptomator.Cryptomator -s -v "${{ inputs.releaseTag }}" -u "$installerUrl" -t ${{ secrets.CRYPTOBOT_WINGET_TOKEN }} + shell: pwsh diff --git a/.gitignore b/.gitignore index 5c84c0dfb..796458fe6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,25 +5,9 @@ *.war *.ear -# Eclipse Settings Files # -.settings -.project -.classpath - # Maven # target/ pom.xml.versionsBackup -# IntelliJ Settings Files (https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems) # -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/shelf -.idea/dictionaries/** -!.idea/dictionaries/dict_* -.idea/compiler.xml -.idea/jarRepositories.xml -.idea/uiDesigner.xml -.idea/**/libraries/ -*.iml - +# Java Crash Logs hs_err_pid*.log \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..8e78cfe58 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,13 @@ +# see https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems + +# Default ignored files +/shelf/ +/workspace.xml +/usage.statistics.xml +/dictionaries/ + +# generated from Maven +/jarRepositories.xml +/modules.xml +/*.iml +/libraries/*.xml \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..18e7c76e0 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 4731638fd..e5d629592 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/.idea/runConfigurations/Cryptomator_Linux.xml b/.idea/runConfigurations/Cryptomator_Linux.xml index 81c2da004..6378f9a00 100644 --- a/.idea/runConfigurations/Cryptomator_Linux.xml +++ b/.idea/runConfigurations/Cryptomator_Linux.xml @@ -2,7 +2,7 @@