825c0142ff6572edc7b3d8f9c9ce1bf84435a0ee
.github/workflows/create-docker-image.yml
| ... | ... | @@ -17,6 +17,18 @@ jobs: |
| 17 | 17 | if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} |
| 18 | 18 | runs-on: ubuntu-latest |
| 19 | 19 | steps: |
| 20 | + - name: Convert repo name to lowercase GHCR package |
|
| 21 | + id: ghcr |
|
| 22 | + env: |
|
| 23 | + GITHUB_REPOSITORY: ${{ github.repository }} |
|
| 24 | + run: | |
|
| 25 | + # $GITHUB_REPOSITORY is in format owner/repo |
|
| 26 | + OWNER=${GITHUB_REPOSITORY%%/*} # extract owner |
|
| 27 | + REPO=${GITHUB_REPOSITORY##*/} # extract repo |
|
| 28 | + OWNER_LOWER=$(echo "$OWNER" | tr '[:upper:]' '[:lower:]') # lowercase owner |
|
| 29 | + REPO_LOWER=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') # lowercase repo |
|
| 30 | + PACKAGE="$OWNER_LOWER/$REPO_LOWER" |
|
| 31 | + echo "PACKAGE=${PACKAGE}" >> $GITHUB_OUTPUT |
|
| 20 | 32 | - name: Checkout |
| 21 | 33 | uses: actions/checkout@v4 |
| 22 | 34 | with: |
| ... | ... | @@ -50,7 +62,7 @@ jobs: |
| 50 | 62 | - name: Download release |
| 51 | 63 | shell: bash |
| 52 | 64 | run: | |
| 53 | - RELEASE_TAR_GZ_FILENAME=$( configuration/github-download-release-assets.sh ${{ secrets.GITHUB_TOKEN }} ${{ env.RELEASE_PREFIX }} ) |
|
| 65 | + RELEASE_TAR_GZ_FILENAME=$( configuration/github-download-release-assets.sh ${{ secrets.GITHUB_TOKEN }} ${{ env.RELEASE_PREFIX }} ${{ github.repository }} ) |
|
| 54 | 66 | RELEASE=$( echo ${RELEASE_TAR_GZ_FILENAME} | sed -e 's/\.tar\.gz$//' ) |
| 55 | 67 | if [ -n ${RELEASE_TAR_GZ_FILENAME} ]; then |
| 56 | 68 | mv ${RELEASE_TAR_GZ_FILENAME} docker/ |
| ... | ... | @@ -60,7 +72,7 @@ jobs: |
| 60 | 72 | uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0 |
| 61 | 73 | with: |
| 62 | 74 | build-args: RELEASE=${{ env.RELEASE }} |
| 63 | - tags: ghcr.io/sap/sailing-analytics:${{ env.RELEASE }}${{ env.BRANCH == 'main' && github.event.inputs.release == '' && ',ghcr.io/sap/sailing-analytics:latest' || env.BRANCH == 'docker-17' && github.event.inputs.release == '' && ',ghcr.io/sap/sailing-analytics:latest-17' || env.BRANCH == 'docker-21' && github.event.inputs.release == '' && ',ghcr.io/sap/sailing-analytics:latest-21' || env.BRANCH == 'docker-24' && github.event.inputs.release == '' && ',ghcr.io/sap/sailing-analytics:latest-24' || '' }} |
|
| 75 | + tags: ghcr.io/${{steps.ghcr.outputs.PACKAGE}}:${{ env.RELEASE }}${{ env.BRANCH == 'main' && github.event.inputs.release == '' && format(',ghcr.io/{0}:latest', steps.ghcr.outputs.PACKAGE) || env.BRANCH == 'docker-17' && github.event.inputs.release == '' && format(',ghcr.io/{0}:latest-17', steps.ghcr.outputs.PACKAGE) || env.BRANCH == 'docker-21' && github.event.inputs.release == '' && format(',ghcr.io/{0}:latest-21', steps.ghcr.outputs.PACKAGE) || env.BRANCH == 'docker-24' && github.event.inputs.release == '' && format(',ghcr.io/{0}:latest-24', steps.ghcr.outputs.PACKAGE) || '' }} |
|
| 64 | 76 | annotations: | |
| 65 | 77 | maintainer=axel.uhl@sap.com |
| 66 | 78 | index:org.opencontainers.image.title=Sailing Analytics |
.github/workflows/merge-main-into-docker-17.yml
| ... | ... | @@ -1,29 +0,0 @@ |
| 1 | -name: Merge main branch into docker-24 after successful build |
|
| 2 | -on: |
|
| 3 | - workflow_run: |
|
| 4 | - workflows: [release] |
|
| 5 | - types: [completed] |
|
| 6 | - branches: [main] |
|
| 7 | - workflow_dispatch: {} |
|
| 8 | -jobs: |
|
| 9 | - merge-main-into-docker-24: |
|
| 10 | - permissions: |
|
| 11 | - contents: write |
|
| 12 | - if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} |
|
| 13 | - runs-on: ubuntu-latest |
|
| 14 | - steps: |
|
| 15 | - - name: Checkout |
|
| 16 | - uses: actions/checkout@v4 |
|
| 17 | - with: |
|
| 18 | - ref: docker-24 |
|
| 19 | - fetch-depth: 0 # fetch the whole thing to make sure the histories merge |
|
| 20 | - - name: Merge main into docker-24 |
|
| 21 | - uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # v1.4.0 |
|
| 22 | - env: |
|
| 23 | - GH_TOKEN: ${{ secrets.REPO_TOKEN_FOR_MERGE_AND_PUSH }} |
|
| 24 | - with: |
|
| 25 | - type: now |
|
| 26 | - from_branch: main |
|
| 27 | - target_branch: docker-24 |
|
| 28 | - message: Auto-merging main into docker-24 after successful release build |
|
| 29 | - github_token: ${{ secrets.REPO_TOKEN_FOR_MERGE_AND_PUSH }} |
.github/workflows/merge-main-into-docker-24.yml
| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | +name: Merge main branch into docker-24 after successful build |
|
| 2 | +on: |
|
| 3 | + workflow_run: |
|
| 4 | + workflows: [release] |
|
| 5 | + types: [completed] |
|
| 6 | + branches: [main] |
|
| 7 | + workflow_dispatch: {} |
|
| 8 | +jobs: |
|
| 9 | + merge-main-into-docker-24: |
|
| 10 | + permissions: |
|
| 11 | + contents: write |
|
| 12 | + if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} |
|
| 13 | + runs-on: ubuntu-latest |
|
| 14 | + steps: |
|
| 15 | + - name: Checkout |
|
| 16 | + uses: actions/checkout@v4 |
|
| 17 | + with: |
|
| 18 | + ref: docker-24 |
|
| 19 | + fetch-depth: 0 # fetch the whole thing to make sure the histories merge |
|
| 20 | + - name: Merge main into docker-24 |
|
| 21 | + uses: devmasx/merge-branch@854d3ac71ed1e9deb668e0074781b81fdd6e771f # v1.4.0 |
|
| 22 | + env: |
|
| 23 | + GH_TOKEN: ${{ secrets.REPO_TOKEN_FOR_MERGE_AND_PUSH }} |
|
| 24 | + with: |
|
| 25 | + type: now |
|
| 26 | + from_branch: main |
|
| 27 | + target_branch: docker-24 |
|
| 28 | + message: Auto-merging main into docker-24 after successful release build |
|
| 29 | + github_token: ${{ secrets.REPO_TOKEN_FOR_MERGE_AND_PUSH }} |
.github/workflows/release.yml
| ... | ... | @@ -5,6 +5,7 @@ on: |
| 5 | 5 | - 'wiki/**' |
| 6 | 6 | - '.github/workflows/*' |
| 7 | 7 | - '**/*.md' |
| 8 | + - 'README.md' |
|
| 8 | 9 | workflow_dispatch: |
| 9 | 10 | inputs: |
| 10 | 11 | skip_tests: |
| ... | ... | @@ -103,7 +104,7 @@ jobs: |
| 103 | 104 | AWS_S3_TEST_S3ACCESSID: ${{ secrets.AWS_S3_TEST_S3ACCESSID }} |
| 104 | 105 | AWS_S3_TEST_S3ACCESSKEY: ${{ secrets.AWS_S3_TEST_S3ACCESSKEY }} |
| 105 | 106 | GEONAMES_ORG_USERNAMES: ${{ secrets.GEONAMES_ORG_USERNAMES }} |
| 106 | - GOOGLE_MAPS_AUTHENTICATION_PARAMS: ${{ secrets.GOOGLE_MAPS_AUTHENTICATIONPARAMS }} |
|
| 107 | + GOOGLE_MAPS_AUTHENTICATION_PARAMS: ${{ secrets.GOOGLE_MAPS_AUTHENTICATION_PARAMS }} |
|
| 107 | 108 | APP_PARAMETERS: "-Daws.region=eu-west-1" |
| 108 | 109 | JAVA8_HOME: ${{env.JAVA_HOME_8_X64}} |
| 109 | 110 | run: | |
README.md
| ... | ... | @@ -32,11 +32,11 @@ Based on the ``docker/docker-compose.yml`` definition you should end up with thr |
| 32 | 32 | |
| 33 | 33 | Try a request to [``http://127.0.0.1:8888/index.html``](http://127.0.0.1:8888/index.html) or [``http://127.0.0.1:8888/gwt/status``](http://127.0.0.1:8888/gwt/status) to see if things worked. |
| 34 | 34 | |
| 35 | -To use Java 17, use the ``docker-compose-17.yml`` file instead: |
|
| 35 | +To use Java 24, use the ``docker-compose-24.yml`` file instead: |
|
| 36 | 36 | |
| 37 | 37 | ``` |
| 38 | 38 | cd docker |
| 39 | - docker-compose -f docker-compose-17.yml up |
|
| 39 | + docker-compose -f docker-compose-24.yml up |
|
| 40 | 40 | ``` |
| 41 | 41 | |
| 42 | 42 | ## Requirements |
| ... | ... | @@ -74,12 +74,123 @@ See [here](https://www.sapsailing.com/gwt/Home.html#/imprint/:) for a list of co |
| 74 | 74 | |
| 75 | 75 | ## Building and Running |
| 76 | 76 | |
| 77 | -This assumes you have completed the onboarding (see again [here](https://wiki.sapsailing.com/wiki/howto/onboarding)) successfully. To build, then invoke |
|
| 77 | +Builds usually run on [GitHub Actions](https://github.com/SAP/sailing-analytics/actions/workflows/release.yml) upon every push. A few repository secrets ensure that the build process has the permissions it needs. Pushes to the ``main``, ``docker-24`` and ``releases/*`` branches also publish a [release](https://github.com/SAP/sailing-analytics/releases) after a successful build. |
|
| 78 | + |
|
| 79 | +There are two options for building, detailed below; for both, you need to fulfill a few prerequisites. |
|
| 80 | + |
|
| 81 | +### Prerequisites |
|
| 82 | + |
|
| 83 | +If you have forked the repository and would like to run your own build, you will need the following prerequisites: |
|
| 84 | + |
|
| 85 | +#### Google Maps API Key |
|
| 86 | + |
|
| 87 | +Create or log on to your Google account and go to the [Google Cloud Console](https://console.cloud.google.com/apis/) and create an API key at least for the Maps JavaScript API. To later run the full product, while you're here, you can also create an API key for the YouTube Data API v3. |
|
| 88 | + |
|
| 89 | +#### AWS S3 Bucket for Upload Tests |
|
| 90 | + |
|
| 91 | +The build runs integration tests using the AWS API, requiring an access key with permission to upload to a bucket called ``sapsailing-automatic-upload-test``. Create that bucket in your AWS S3 environment. You can create an IAM user with CLI access and a permission policy that restricts write permissions to just that test bucket. You have to create the bucked in AWS region ``eu-west-1``. A permission policy for that user can look like this: |
|
| 92 | + |
|
| 93 | +``` |
|
| 94 | +{ |
|
| 95 | + "Version": "2012-10-17", |
|
| 96 | + "Statement": [ |
|
| 97 | + { |
|
| 98 | + "Sid": "Stmt1422015883000", |
|
| 99 | + "Effect": "Allow", |
|
| 100 | + "Action": [ |
|
| 101 | + "s3:AbortMultipartUpload", |
|
| 102 | + "s3:DeleteObject", |
|
| 103 | + "s3:DeleteObjectVersion", |
|
| 104 | + "s3:GetBucketAcl", |
|
| 105 | + "s3:GetBucketCORS", |
|
| 106 | + "s3:GetBucketLocation", |
|
| 107 | + "s3:GetBucketLogging", |
|
| 108 | + "s3:GetBucketNotification", |
|
| 109 | + "s3:GetBucketPolicy", |
|
| 110 | + "s3:GetBucketTagging", |
|
| 111 | + "s3:GetBucketVersioning", |
|
| 112 | + "s3:GetBucketWebsite", |
|
| 113 | + "s3:GetLifecycleConfiguration", |
|
| 114 | + "s3:GetObject", |
|
| 115 | + "s3:GetObjectAcl", |
|
| 116 | + "s3:GetObjectTorrent", |
|
| 117 | + "s3:GetObjectVersion", |
|
| 118 | + "s3:GetObjectVersionAcl", |
|
| 119 | + "s3:GetObjectVersionTorrent", |
|
| 120 | + "s3:ListAllMyBuckets", |
|
| 121 | + "s3:ListBucket", |
|
| 122 | + "s3:ListBucketMultipartUploads", |
|
| 123 | + "s3:ListBucketVersions", |
|
| 124 | + "s3:ListMultipartUploadParts", |
|
| 125 | + "s3:PutBucketLogging", |
|
| 126 | + "s3:PutBucketNotification", |
|
| 127 | + "s3:PutBucketPolicy", |
|
| 128 | + "s3:PutBucketTagging", |
|
| 129 | + "s3:PutBucketVersioning", |
|
| 130 | + "s3:PutBucketWebsite", |
|
| 131 | + "s3:PutLifecycleConfiguration", |
|
| 132 | + "s3:PutObject", |
|
| 133 | + "s3:PutObjectAcl", |
|
| 134 | + "s3:PutObjectVersionAcl", |
|
| 135 | + "s3:RestoreObject" |
|
| 136 | + ], |
|
| 137 | + "Resource": [ |
|
| 138 | + "arn:aws:s3:::sapsailing-automatic-upload-test/*", |
|
| 139 | + "arn:aws:s3:::sapsailing-automatic-upload-test" |
|
| 140 | + ] |
|
| 141 | + } |
|
| 142 | + ] |
|
| 143 | +} |
|
| 144 | +``` |
|
| 145 | + |
|
| 146 | +Create an access key for that user and note key ID and secret. |
|
| 147 | + |
|
| 148 | +#### Account(s) for geonames.org |
|
| 149 | + |
|
| 150 | +The build runs integration tests against [geonames.org](https://geonames.org). Use their login/sign-up form to create your user account and note its username. |
|
| 151 | + |
|
| 152 | +### Get the GitHub Actions build to work in your forked repository |
|
| 153 | + |
|
| 154 | +Assign the IDs and secrets from the prerequisites to repository secrets in your forked repository as follows: |
|
| 155 | + |
|
| 156 | +``` |
|
| 157 | +AWS_S3_TEST_S3ACCESSID: {your-S3-test-bucket-upload-token-ID} |
|
| 158 | +AWS_S3_TEST_S3ACCESSKEY: {key-for-your-S3-token} |
|
| 159 | +GEONAMES_ORG_USERNAMES: {comma-separated-list-of-geonames.org-usernames} |
|
| 160 | +GOOGLE_MAPS_AUTHENTICATION_PARAMS: key={your-Google-Maps-API-key} |
|
| 161 | +``` |
|
| 162 | + |
|
| 163 | +Then, manually trigger the ``release`` workflow with default options. You find the "Run workflow" drop-down in your forked repository under ``https://github.com/{your-github-user}/[your-repository-name}/actions/workflows/release.yml``. |
|
| 164 | + |
|
| 165 | +Release builds will trigger the ``create-docker-image`` workflow which will produce a Docker image of your release and publish it as a "ghcr" package in your repository. Note that package names are computed from the repository name by converting the latter to all lowercase characters. If you want to use your packages in the docker-compose configurations from the ``docker/`` folder, make sure to adjust the package name so it points to your own fork's package registry. |
|
| 166 | + |
|
| 167 | +If you want automatic validation of your changes to the ``main`` branch also for newer Java versions, you can use the ``merge-main-into-docker-24`` workflow. It requires another secret: |
|
| 168 | + |
|
| 169 | +``` |
|
| 170 | +REPO_TOKEN_FOR_MERGE_AND_PUSH: {a-GitHub-token-enabled-for-push} |
|
| 171 | +``` |
|
| 172 | + |
|
| 173 | +The workflow will launch automatically after a release has been performed for the ``main`` branch and will try to merge the latest ``main`` branch into ``docker-24`` and pushing the merge result if the merge was successful. This will then trigger a build for the ``docker-24`` branch which, if successul, will in turn produce a release and a docker image for use with Java 24. |
|
| 174 | + |
|
| 175 | +### Run a build locally |
|
| 176 | + |
|
| 177 | +This assumes you have completed the onboarding (see again [here](https://wiki.sapsailing.com/wiki/howto/onboarding)) successfully, including the Maven-specific parts such as having Maven installed (>= 3.9.x) and having a valid ``toolchains.xml`` file in your ~/.m2 folder. Furthermore, set and export the following environment variables: |
|
| 178 | + |
|
| 179 | +``` |
|
| 180 | +export AWS_S3_TEST_S3ACCESSID={your-S3-test-bucket-upload-token-ID} |
|
| 181 | +export AWS_S3_TEST_S3ACCESSKEY={key-for-your-S3-token} |
|
| 182 | +export GEONAMES_ORG_USERNAMES={comma-separated-list-of-geonames.org-usernames} |
|
| 183 | +export GOOGLE_MAPS_AUTHENTICATION_PARAMS=key={your-Google-Maps-API-key} |
|
| 184 | +export JAVA8_HOME={location-of-your-JDK8} |
|
| 185 | +export JAVA_HOME={location-of-your-JDK17-or-newer} |
|
| 186 | +``` |
|
| 187 | + |
|
| 188 | +To build, then invoke |
|
| 78 | 189 | |
| 79 | 190 | ``` |
| 80 | 191 | configuration/buildAndUpdateProduct.sh build |
| 81 | 192 | ``` |
| 82 | -This will build the Android companion apps first, then the web application. If the build was successful you can install the product locally by invoking |
|
| 193 | +This will build the Android companion apps first, then the web application. If you lack a proper Android SDK set-up, consider using the ``-a`` option to skip building the Android apps. If the build was successful you can install the product locally by invoking |
|
| 83 | 194 | |
| 84 | 195 | ``` |
| 85 | 196 | configuration/buildAndUpdateProduct.sh install [ -s <server-name> ] |
| ... | ... | @@ -99,9 +210,9 @@ Run the ``buildAndUpdateProduct.sh`` without any arguments to see the sub-comman |
| 99 | 210 | |
| 100 | 211 | ## Downloading, Installing and Running an Official Release |
| 101 | 212 | |
| 102 | -You need to have Java 8 installed. Get one from [here](https://tools.eu1.hana.ondemand.com/#cloud). Either ensure that this JVM's ``java`` executable in on the ``PATH`` or set ``JAVA_HOME`` appropriately. |
|
| 213 | +You need to have Java 8 installed. Get one from, e.g., [here](https://tools.eu1.hana.ondemand.com/#cloud). Either ensure that this JVM's ``java`` executable in on the ``PATH`` or set ``JAVA_HOME`` appropriately. |
|
| 103 | 214 | |
| 104 | -At [https://releases.sapsailing.com](https://releases.sapsailing.com) you find official product builds. To fetch and install one of them, make an empty directory, change into it and run the ``refreshInstance.sh`` command, e.g., like this: |
|
| 215 | +At [https://github.com/SAP/sailing-analytics/releases](https://github.com/SAP/sailing-analytics/releases) you find official product builds. To fetch and install one of them, make an empty directory, change into it and run the ``refreshInstance.sh`` command, e.g., like this: |
|
| 105 | 216 | ``` |
| 106 | 217 | mkdir sailinganalytics |
| 107 | 218 | cd sailinganalytics |
| ... | ... | @@ -113,7 +224,6 @@ This will download and install the latest release and configure it such that it |
| 113 | 224 | In addition to the necessary ``MONGODB_URI`` variable you may need to inject a few secrets into your runtime environment: |
| 114 | 225 | |
| 115 | 226 | - ``MANAGE2SAIL_ACCESS_TOKEN`` access token for result and regatta structure import from the Manage2Sail regatta management system |
| 116 | -- ``IGTIMI_CLIENT_ID`` / ``IGTIMI_CLIENT_SECRET`` credentials for ``igtimi.com`` in case you have one or more WindBot devices that you would like to integrate with |
|
| 117 | 227 | - ``GOOGLE_MAPS_AUTHENTICATION_PARAMS`` as in ``"key=..."`` or ``"client=..."``, required to display the Google Map in the race viewer. Obtain a Google Maps key from the Google Cloud Developer console, e.g., [here](https://console.cloud.google.com/apis/dashboard). |
| 118 | 228 | - ``YOUTUBE_API_KEY`` as in ``"key=..."``, required to analyze time stamps and durations of YouTube videos when linking to races. Obtain a YouTube API key from the Google Cloud Developer console, e.g., [here](https://console.cloud.google.com/apis/dashboard). |
| 119 | 229 |
configuration/github-copy-release-to-sapsailing-com.sh
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | # produce false matches for the "main-" prefix. |
| 18 | 18 | BEARER_TOKEN="${1}" |
| 19 | 19 | RELEASE_NAME_PREFIX="${2}" |
| 20 | -RELEASE_TAR_GZ_FILE_NAME=$( `dirname "${0}"`/github-download-release-assets.sh "${BEARER_TOKEN}" "${RELEASE_NAME_PREFIX}" ) |
|
| 20 | +RELEASE_TAR_GZ_FILE_NAME=$( `dirname "${0}"`/github-download-release-assets.sh "${BEARER_TOKEN}" "${RELEASE_NAME_PREFIX}" SAP/sailing-analytics ) |
|
| 21 | 21 | if [ "${RELEASE_TAR_GZ_FILE_NAME}" != "" ]; then |
| 22 | 22 | RELEASE_NAME=$( echo ${RELEASE_TAR_GZ_FILE_NAME} | sed -e 's/^\(.*\)-\([0-9]*\).tar.gz$/\1/' ) |
| 23 | 23 | RELEASE_TIMESTAMP=$( echo ${RELEASE_TAR_GZ_FILE_NAME} | sed -e 's/^\(.*\)-\([0-9]*\).tar.gz$/\2/' ) |
configuration/github-download-release-assets.sh
| ... | ... | @@ -5,9 +5,9 @@ |
| 5 | 5 | # always be 0. |
| 6 | 6 | # |
| 7 | 7 | # Usage: |
| 8 | -# ./github-download-release-assets.sh {BEARER_TOKEN} {release-name-prefix} |
|
| 8 | +# ./github-download-release-assets.sh {BEARER_TOKEN} {release-name-prefix} {repository-name} |
|
| 9 | 9 | # For example: |
| 10 | -# ./github-download-release-assets.sh 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 main- |
|
| 10 | +# ./github-download-release-assets.sh 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 main- SAP/sailing-analytics |
|
| 11 | 11 | # which will download the latest release tar.gz and release-notes.txt of the main branch (main-xxxxxxxxxxx). |
| 12 | 12 | # Note the "-" at the end of the "main-" prefix specifier; this way we're making name |
| 13 | 13 | # clashes with releases whose name happens to start with "main" unlikely. This |
| ... | ... | @@ -15,7 +15,8 @@ |
| 15 | 15 | # produce false matches for the "main-" prefix. |
| 16 | 16 | BEARER_TOKEN="${1}" |
| 17 | 17 | RELEASE_NAME_PREFIX="${2}" |
| 18 | -RELEASES=$( curl -L -H 'Authorization: Bearer '${BEARER_TOKEN} https://api.github.com/repos/SAP/sailing-analytics/releases 2>/dev/null ) |
|
| 18 | +GITHUB_REPOSITORY="${3}" |
|
| 19 | +RELEASES=$( curl -L -H 'Authorization: Bearer '${BEARER_TOKEN} https://api.github.com/repos/${GITHUB_REPOSITORY}/releases 2>/dev/null ) |
|
| 19 | 20 | RELEASE_NOTES_TXT_ASSET_ID=$( echo "${RELEASES}" | jq -r 'sort_by(.published_at) | reverse | map(select(.name | startswith("'${RELEASE_NAME_PREFIX}'")))[0].assets[] | select(.content_type=="text/plain").id' 2>/dev/null) |
| 20 | 21 | if [ "$?" -ne "0" ]; then |
| 21 | 22 | echo "No release with prefix ${RELEASE_NAME_PREFIX} found. Not trying to download/upload anything." >&2 |
| ... | ... | @@ -26,7 +27,7 @@ else |
| 26 | 27 | RELEASE_TIMESTAMP=$( echo ${RELEASE_FULL_NAME} | sed -e 's/^\(.*\)-\([0-9]*\)$/\2/' ) |
| 27 | 28 | echo "Found release ${RELEASE_FULL_NAME} with name ${RELEASE_NAME} and time stamp ${RELEASE_TIMESTAMP}, notes ID is ${RELEASE_NOTES_TXT_ASSET_ID}, tarball ID is ${RELEASE_TAR_GZ_ASSET_ID}" >&2 |
| 28 | 29 | RELEASE_TAR_GZ_FILE_NAME="${RELEASE_FULL_NAME}.tar.gz" |
| 29 | - curl -o "${RELEASE_TAR_GZ_FILE_NAME}" -L -H 'Accept: application/octet-stream' -H 'Authorization: Bearer '${BEARER_TOKEN} 'https://api.github.com/repos/SAP/sailing-analytics/releases/assets/'${RELEASE_TAR_GZ_ASSET_ID} |
|
| 30 | - curl -o release-notes.txt -L -H 'Accept: application/octet-stream' -H 'Authorization: Bearer '${BEARER_TOKEN} 'https://api.github.com/repos/SAP/sailing-analytics/releases/assets/'${RELEASE_NOTES_TXT_ASSET_ID} |
|
| 30 | + curl -o "${RELEASE_TAR_GZ_FILE_NAME}" -L -H 'Accept: application/octet-stream' -H 'Authorization: Bearer '${BEARER_TOKEN} 'https://api.github.com/repos/'${GITHUB_REPOSITORY}'/releases/assets/'${RELEASE_TAR_GZ_ASSET_ID} |
|
| 31 | + curl -o release-notes.txt -L -H 'Accept: application/octet-stream' -H 'Authorization: Bearer '${BEARER_TOKEN} 'https://api.github.com/repos/'${GITHUB_REPOSITORY}'/releases/assets/'${RELEASE_NOTES_TXT_ASSET_ID} |
|
| 31 | 32 | echo "${RELEASE_TAR_GZ_FILE_NAME}" |
| 32 | 33 | fi |
configuration/github-download-workflow-artifacts.sh
| ... | ... | @@ -12,12 +12,13 @@ |
| 12 | 12 | # an exit status of 2 is returned. |
| 13 | 13 | BRANCH="${1}" |
| 14 | 14 | BEARER_TOKEN="${2}" |
| 15 | +GITHUB_REPOSITORY="${3}" |
|
| 15 | 16 | UNIX_TIME=$( date +%s ) |
| 16 | 17 | UNIX_DATE=$( date --iso-8601=second ) |
| 17 | 18 | UNIX_TIME_YESTERDAY=$(( UNIX_TIME - 10*24*3600 )) # look back ten days in time, trying to catch even re-runs of older jobs |
| 18 | 19 | DATE_YESTERDAY=$( date --iso-8601=second -d @${UNIX_TIME_YESTERDAY} ) |
| 19 | 20 | HEADERS_FILE=$( mktemp headersXXXXX ) |
| 20 | -NEXT_PAGE="https://api.github.com/repos/SAP/sailing-analytics/actions/runs?created=${DATE_YESTERDAY/+/%2B}..${UNIX_DATE/+/%2B}&per_page=100" |
|
| 21 | +NEXT_PAGE="https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runs?created=${DATE_YESTERDAY/+/%2B}..${UNIX_DATE/+/%2B}&per_page=100" |
|
| 21 | 22 | ARTIFACTS_JSON="" |
| 22 | 23 | LATEST_RUN_STARTED_AT="0000-00-00T00:00:00Z" |
| 23 | 24 | # Now go through the pages as long as we have a non-empty NEXT_PAGE URL and find the completed "release" workflow that was started last |
docker/makeImageForLatestRelease
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | -release_prefix=$1 |
|
| 2 | +release_prefix="$1" |
|
| 3 | +GITHUB_REPOSITORY="$2" |
|
| 4 | +OWNER=${GITHUB_REPOSITORY%%/*} |
|
| 5 | +OWNER_LOWER=$(echo "$OWNER" | tr '[:upper:]' '[:lower:]') |
|
| 6 | +REPO=${GITHUB_REPOSITORY##*/} |
|
| 7 | +REPO_LOWER=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') |
|
| 8 | +PACKAGE="$OWNER_LOWER/$REPO_LOWER" |
|
| 3 | 9 | GITROOT="`dirname $0`/.." |
| 4 | 10 | DOCKERDIR="${GITROOT}/docker" |
| 5 | 11 | DOCKERFILE="$DOCKERDIR/Dockerfile" |
| ... | ... | @@ -8,7 +14,7 @@ if [ "${release_prefix}" = "" ]; then |
| 8 | 14 | release_prefix="main-" |
| 9 | 15 | fi |
| 10 | 16 | pushd "${DOCKERDIR}" |
| 11 | -RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" ) |
|
| 17 | +RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" "${GITHUB_REPOSITORY}" ) |
|
| 12 | 18 | if [ "${RELEASE_TAR_GZ_FILENAME}" = "" ]; then |
| 13 | 19 | echo "No release with prefix ${release_prefix} found" >&2 |
| 14 | 20 | else |
| ... | ... | @@ -20,7 +26,7 @@ else |
| 20 | 26 | cp "$GITROOT/java/target/configuration/JavaSE-11.profile" "$DOCKERDIR" |
| 21 | 27 | cd "$DOCKERDIR" |
| 22 | 28 | docker buildx create --name=container --driver=docker-container --use --bootstrap |
| 23 | - docker buildx build --builder=container --platform=linux/amd64,linux/arm64 --build-arg RELEASE=${release} -t ghcr.io/sap/sailing-analytics:${release} --push . |
|
| 29 | + docker buildx build --builder=container --platform=linux/amd64,linux/arm64 --build-arg RELEASE=${release} -t ghcr.io/${PACKAGE}:${release} --push . |
|
| 24 | 30 | echo "Cleaning up..." |
| 25 | 31 | rm start env.sh JavaSE-11.profile ${RELEASE_TAR_GZ_FILENAME} release-notes.txt |
| 26 | 32 | fi |
docker/makeImageForLatestRelease-arm
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | -release_prefix=$1 |
|
| 2 | +release_prefix="$1" |
|
| 3 | +GITHUB_REPOSITORY="$2" |
|
| 4 | +OWNER=${GITHUB_REPOSITORY%%/*} |
|
| 5 | +OWNER_LOWER=$(echo "$OWNER" | tr '[:upper:]' '[:lower:]') |
|
| 6 | +REPO=${GITHUB_REPOSITORY##*/} |
|
| 7 | +REPO_LOWER=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') |
|
| 8 | +PACKAGE="$OWNER_LOWER/$REPO_LOWER" |
|
| 3 | 9 | GITROOT="`dirname $0`/.." |
| 4 | 10 | DOCKERDIR="${GITROOT}/docker" |
| 5 | 11 | DOCKERFILE="$DOCKERDIR/Dockerfile" |
| ... | ... | @@ -8,7 +14,7 @@ if [ "${release_prefix}" = "" ]; then |
| 8 | 14 | release_prefix="main-" |
| 9 | 15 | fi |
| 10 | 16 | pushd "${DOCKERDIR}" |
| 11 | -RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" ) |
|
| 17 | +RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" "${GITHUB_REPOSITORY}" ) |
|
| 12 | 18 | if [ "${RELEASE_TAR_GZ_FILENAME}" = "" ]; then |
| 13 | 19 | echo "No release with prefix ${release_prefix} found" >&2 |
| 14 | 20 | else |
| ... | ... | @@ -19,13 +25,13 @@ else |
| 19 | 25 | cp "$GITROOT/java/target/start" "$DOCKERDIR" |
| 20 | 26 | cp "$GITROOT/java/target/configuration/JavaSE-11.profile" "$DOCKERDIR" |
| 21 | 27 | cd "$DOCKERDIR" |
| 22 | - docker build --build-arg RELEASE=${release} -t ghcr.io/sap/sailing-analytics:${release}-arm . |
|
| 28 | + docker build --build-arg RELEASE=${release} -t ghcr.io/${PACKAGE}:${release}-arm . |
|
| 23 | 29 | echo "Cleaning up..." |
| 24 | 30 | rm start env.sh JavaSE-11.profile ${RELEASE_TAR_GZ_FILENAME} release-notes.txt |
| 25 | - docker push ghcr.io/sap/sailing-analytics:${release}-arm |
|
| 31 | + docker push ghcr.io/${PACKAGE}:${release}-arm |
|
| 26 | 32 | if [ "$SET_LATEST" = "1" ]; then |
| 27 | - docker tag ghcr.io/sap/sailing-analytics:${release}-arm ghcr.io/sap/sailing-analytics:latest-arm |
|
| 28 | - docker push ghcr.io/sap/sailing-analytics:latest-arm |
|
| 33 | + docker tag ghcr.io/${PACKAGE}:${release}-arm ghcr.io/${PACKAGE}:latest-arm |
|
| 34 | + docker push ghcr.io/${PACKAGE}:latest-arm |
|
| 29 | 35 | fi |
| 30 | 36 | fi |
| 31 | 37 | popd |
docker/makeImageForLatestRelease-on-sapmachine11
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | -release_prefix=$1 |
|
| 2 | +release_prefix="$1" |
|
| 3 | +GITHUB_REPOSITORY="$2" |
|
| 4 | +OWNER=${GITHUB_REPOSITORY%%/*} |
|
| 5 | +OWNER_LOWER=$(echo "$OWNER" | tr '[:upper:]' '[:lower:]') |
|
| 6 | +REPO=${GITHUB_REPOSITORY##*/} |
|
| 7 | +REPO_LOWER=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') |
|
| 8 | +PACKAGE="$OWNER_LOWER/$REPO_LOWER" |
|
| 3 | 9 | GITROOT="`dirname $0`/.." |
| 4 | 10 | DOCKERDIR="${GITROOT}/docker" |
| 5 | 11 | DOCKERFILE="$DOCKERDIR/Dockerfile" |
| ... | ... | @@ -8,7 +14,7 @@ if [ "${release_prefix}" = "" ]; then |
| 8 | 14 | release_prefix="docker-11-" |
| 9 | 15 | fi |
| 10 | 16 | pushd "${DOCKERDIR}" |
| 11 | -RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" ) |
|
| 17 | +RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" "${GITHUB_REPOSITORY}" ) |
|
| 12 | 18 | if [ "${RELEASE_TAR_GZ_FILENAME}" = "" ]; then |
| 13 | 19 | echo "No release with prefix ${release_prefix} found" >&2 |
| 14 | 20 | else |
| ... | ... | @@ -19,13 +25,13 @@ else |
| 19 | 25 | cp "$GITROOT/java/target/start" "$DOCKERDIR" |
| 20 | 26 | cp "$GITROOT/java/target/configuration/JavaSE-11.profile" "$DOCKERDIR" |
| 21 | 27 | cd "$DOCKERDIR" |
| 22 | - docker build --build-arg RELEASE=${release} -t ghcr.io/sap/sailing-analytics:${release} -f Dockerfile_sapsailing_on_sapmachine11 . |
|
| 28 | + docker build --build-arg RELEASE=${release} -t ghcr.io/${PACKAGE}:${release} -f Dockerfile_sapsailing_on_sapmachine11 . |
|
| 23 | 29 | echo "Cleaning up..." |
| 24 | 30 | rm start env.sh JavaSE-11.profile ${RELEASE_TAR_GZ_FILENAME} release-notes.txt |
| 25 | - docker push ghcr.io/sap/sailing-analytics:${release} |
|
| 31 | + docker push ghcr.io/${PACKAGE}:${release} |
|
| 26 | 32 | if [ "$SET_LATEST" = "1" ]; then |
| 27 | - docker tag ghcr.io/sap/sailing-analytics:${release} ghcr.io/sap/sailing-analytics:latest-11 |
|
| 28 | - docker push ghcr.io/sap/sailing-analytics:latest-11 |
|
| 33 | + docker tag ghcr.io/${PACKAGE}:${release} ghcr.io/${PACKAGE}:latest-11 |
|
| 34 | + docker push ghcr.io/${PACKAGE}:latest-11 |
|
| 29 | 35 | fi |
| 30 | 36 | fi |
| 31 | 37 | popd |
docker/makeImageForLatestRelease-on-sapmachine17
| ... | ... | @@ -1,5 +1,11 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | -release_prefix=$1 |
|
| 2 | +release_prefix="$1" |
|
| 3 | +GITHUB_REPOSITORY="$2" |
|
| 4 | +OWNER=${GITHUB_REPOSITORY%%/*} |
|
| 5 | +OWNER_LOWER=$(echo "$OWNER" | tr '[:upper:]' '[:lower:]') |
|
| 6 | +REPO=${GITHUB_REPOSITORY##*/} |
|
| 7 | +REPO_LOWER=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') |
|
| 8 | +PACKAGE="$OWNER_LOWER/$REPO_LOWER" |
|
| 3 | 9 | GITROOT="`dirname $0`/.." |
| 4 | 10 | DOCKERDIR="${GITROOT}/docker" |
| 5 | 11 | DOCKERFILE="$DOCKERDIR/Dockerfile" |
| ... | ... | @@ -8,7 +14,7 @@ if [ "${release_prefix}" = "" ]; then |
| 8 | 14 | release_prefix="docker-17-" |
| 9 | 15 | fi |
| 10 | 16 | pushd "${DOCKERDIR}" |
| 11 | -RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" ) |
|
| 17 | +RELEASE_TAR_GZ_FILENAME=$( ${GITROOT}/configuration/github-download-release-assets.sh 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 "${release_prefix}" "${GITHUB_REPOSITORY}" ) |
|
| 12 | 18 | if [ "${RELEASE_TAR_GZ_FILENAME}" = "" ]; then |
| 13 | 19 | echo "No release with prefix ${release_prefix} found" >&2 |
| 14 | 20 | else |
| ... | ... | @@ -19,13 +25,13 @@ else |
| 19 | 25 | cp "$GITROOT/java/target/start" "$DOCKERDIR" |
| 20 | 26 | cp "$GITROOT/java/target/configuration/JavaSE-11.profile" "$DOCKERDIR" |
| 21 | 27 | cd "$DOCKERDIR" |
| 22 | - docker build --build-arg RELEASE=${release} -t ghcr.io/sap/sailing-analytics:${release} -f Dockerfile_sapsailing_on_sapmachine17 . |
|
| 28 | + docker build --build-arg RELEASE=${release} -t ghcr.io/${PACKAGE}:${release} -f Dockerfile_sapsailing_on_sapmachine17 . |
|
| 23 | 29 | echo "Cleaning up..." |
| 24 | 30 | rm start env.sh JavaSE-11.profile ${RELEASE_TAR_GZ_FILENAME} release-notes.txt |
| 25 | - docker push ghcr.io/sap/sailing-analytics:${release} |
|
| 31 | + docker push ghcr.io/${PACKAGE}:${release} |
|
| 26 | 32 | if [ "$SET_LATEST" = "1" ]; then |
| 27 | - docker tag ghcr.io/sap/sailing-analytics:${release} ghcr.io/sap/sailing-analytics:latest-17 |
|
| 28 | - docker push ghcr.io/sap/sailing-analytics:latest-17 |
|
| 33 | + docker tag ghcr.io/${PACKAGE}:${release} ghcr.io/${PACKAGE}:latest-17 |
|
| 34 | + docker push ghcr.io/${PACKAGE}:latest-17 |
|
| 29 | 35 | fi |
| 30 | 36 | fi |
| 31 | 37 | popd |
java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/NOAADeclinationImportTest.java
| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.declination.test; |
| 2 | 2 | |
| 3 | 3 | import org.junit.jupiter.api.BeforeEach; |
| 4 | +import org.junit.jupiter.api.Disabled; |
|
| 4 | 5 | |
| 5 | 6 | import com.sap.sailing.declination.impl.NOAAImporterForTesting; |
| 6 | 7 | |
| 8 | +@Disabled("US Government Shutdown around 2025-10-01") |
|
| 7 | 9 | public class NOAADeclinationImportTest extends DeclinationImportTest<NOAAImporterForTesting> { |
| 8 | 10 | @BeforeEach |
| 9 | 11 | public void setUp() { |
java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/NOAADeclinationServiceTest.java
| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.declination.test; |
| 2 | 2 | |
| 3 | 3 | import org.junit.jupiter.api.BeforeEach; |
| 4 | +import org.junit.jupiter.api.Disabled; |
|
| 4 | 5 | |
| 5 | 6 | import com.sap.sailing.declination.impl.NOAAImporter; |
| 6 | 7 | |
| 8 | +@Disabled("US Government Shutdown around 2025-10-01") |
|
| 7 | 9 | public class NOAADeclinationServiceTest extends DeclinationServiceTest<NOAAImporter> { |
| 8 | 10 | @Override |
| 9 | 11 | @BeforeEach |
java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/NOAADeclinationStoreTest.java
| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.declination.test; |
| 2 | 2 | |
| 3 | 3 | import org.junit.jupiter.api.BeforeEach; |
| 4 | +import org.junit.jupiter.api.Disabled; |
|
| 4 | 5 | |
| 5 | 6 | import com.sap.sailing.declination.impl.NOAAImporter; |
| 6 | 7 | |
| 8 | +@Disabled("US Government Shutdown around 2025-10-01") |
|
| 7 | 9 | public class NOAADeclinationStoreTest extends DeclinationStoreTest<NOAAImporter> { |
| 8 | 10 | @Override |
| 9 | 11 | @BeforeEach |
java/com.sap.sailing.declination.test/src/com/sap/sailing/declination/test/NOAASimpleDeclinationTest.java
| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | package com.sap.sailing.declination.test; |
| 2 | 2 | |
| 3 | 3 | import org.junit.jupiter.api.BeforeEach; |
| 4 | +import org.junit.jupiter.api.Disabled; |
|
| 4 | 5 | |
| 5 | 6 | import com.sap.sailing.declination.impl.NOAAImporter; |
| 6 | 7 | |
| 8 | +@Disabled("US Government Shutdown around 2025-10-01") |
|
| 7 | 9 | public class NOAASimpleDeclinationTest extends SimpleDeclinationTest<NOAAImporter> { |
| 8 | 10 | @BeforeEach |
| 9 | 11 | public void setUp() { |
java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/ui/EditCAM.java
| ... | ... | @@ -56,9 +56,7 @@ public class EditCAM extends javax.swing.JDialog { |
| 56 | 56 | */ |
| 57 | 57 | |
| 58 | 58 | // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| 59 | - @SuppressWarnings("serial") |
|
| 60 | 59 | private void initComponents() { |
| 61 | - |
|
| 62 | 60 | jLabel1 = new javax.swing.JLabel(); |
| 63 | 61 | jRaceID = new javax.swing.JTextField(); |
| 64 | 62 | jSeparator1 = new javax.swing.JSeparator(); |
| ... | ... | @@ -73,46 +71,33 @@ public class EditCAM extends javax.swing.JDialog { |
| 73 | 71 | jButton3 = new javax.swing.JButton(); |
| 74 | 72 | jScrollPane1 = new javax.swing.JScrollPane(); |
| 75 | 73 | jMarkList = new javax.swing.JList<ClockAtMarkElement>(); |
| 76 | - |
|
| 77 | 74 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); |
| 78 | - |
|
| 79 | 75 | jLabel1.setText("Race ID:"); |
| 80 | - |
|
| 81 | 76 | jRaceID.setText("jTextField1"); |
| 82 | - |
|
| 83 | 77 | jLabel2.setText("Mark index:"); |
| 84 | - |
|
| 85 | 78 | jMarkIndex.setText("0"); |
| 86 | - |
|
| 87 | 79 | jLabel3.setText("Mark time:"); |
| 88 | - |
|
| 89 | 80 | jMarkTime.setText("12:34:17"); |
| 90 | - |
|
| 91 | 81 | jLabel4.setText("Sail number:"); |
| 92 | - |
|
| 93 | 82 | jSailNumber.setText("w123"); |
| 94 | - |
|
| 95 | 83 | jButton1.setText("Ok"); |
| 96 | 84 | jButton1.addActionListener(new java.awt.event.ActionListener() { |
| 97 | 85 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 98 | 86 | jButton1ActionPerformed(evt); |
| 99 | 87 | } |
| 100 | 88 | }); |
| 101 | - |
|
| 102 | 89 | jButton2.setText("Remove"); |
| 103 | 90 | jButton2.addActionListener(new java.awt.event.ActionListener() { |
| 104 | 91 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 105 | 92 | jButton2ActionPerformed(evt); |
| 106 | 93 | } |
| 107 | 94 | }); |
| 108 | - |
|
| 109 | 95 | jButton3.setText("Add"); |
| 110 | 96 | jButton3.addActionListener(new java.awt.event.ActionListener() { |
| 111 | 97 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 112 | 98 | jButton3ActionPerformed(evt); |
| 113 | 99 | } |
| 114 | 100 | }); |
| 115 | - |
|
| 116 | 101 | jMarkList.setModel(new javax.swing.AbstractListModel<ClockAtMarkElement>() { |
| 117 | 102 | ClockAtMarkElement[] clockAtMarkElements = { new ClockAtMarkElement(1, new Date(), "Item 1"), |
| 118 | 103 | new ClockAtMarkElement(1, new Date(), "Item 2"), new ClockAtMarkElement(1, new Date(), "Item 3"), |
java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/ui/EditCCG.java
| ... | ... | @@ -51,9 +51,7 @@ public class EditCCG extends javax.swing.JDialog { |
| 51 | 51 | */ |
| 52 | 52 | |
| 53 | 53 | // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| 54 | - @SuppressWarnings("serial") |
|
| 55 | 54 | private void initComponents() { |
| 56 | - |
|
| 57 | 55 | jBuoyType = new javax.swing.ButtonGroup(); |
| 58 | 56 | jLabel1 = new javax.swing.JLabel(); |
| 59 | 57 | jRaceID = new javax.swing.JTextField(); |
java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/ui/EditSTL.java
| ... | ... | @@ -49,9 +49,7 @@ public class EditSTL extends javax.swing.JDialog { |
| 49 | 49 | */ |
| 50 | 50 | |
| 51 | 51 | // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| 52 | - @SuppressWarnings("serial") |
|
| 53 | 52 | private void initComponents() { |
| 54 | - |
|
| 55 | 53 | jLabel1 = new javax.swing.JLabel(); |
| 56 | 54 | jRaceID = new javax.swing.JTextField(); |
| 57 | 55 | jSeparator1 = new javax.swing.JSeparator(); |
| ... | ... | @@ -66,47 +64,34 @@ public class EditSTL extends javax.swing.JDialog { |
| 66 | 64 | jButton2 = new javax.swing.JButton(); |
| 67 | 65 | jScrollPane1 = new javax.swing.JScrollPane(); |
| 68 | 66 | jCompetitorList = new javax.swing.JList<Competitor>(); |
| 69 | - |
|
| 70 | 67 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); |
| 71 | - |
|
| 72 | 68 | jLabel1.setText("Race ID:"); |
| 73 | - |
|
| 74 | 69 | jRaceID.setText("jTextField1"); |
| 75 | - |
|
| 76 | 70 | jLabel2.setText("Sail Number:"); |
| 77 | - |
|
| 78 | 71 | jSailNumber.setText("jTextField1"); |
| 79 | - |
|
| 80 | 72 | jLabel3.setText("NOC:"); |
| 81 | - |
|
| 82 | 73 | jNOC.setModel(new javax.swing.DefaultComboBoxModel<String>(new String[] { "AUS", "FRA", "GBR", "GER", "ITA", "USA" })); |
| 83 | 74 | jNOC.setSelectedIndex(2); |
| 84 | - |
|
| 85 | 75 | jLabel4.setText("Name:"); |
| 86 | - |
|
| 87 | 76 | jName.setText("jTextField1"); |
| 88 | - |
|
| 89 | 77 | jButton1.setText("Add"); |
| 90 | 78 | jButton1.addActionListener(new java.awt.event.ActionListener() { |
| 91 | 79 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 92 | 80 | jButton1ActionPerformed(evt); |
| 93 | 81 | } |
| 94 | 82 | }); |
| 95 | - |
|
| 96 | 83 | jRemove.setText("Remove"); |
| 97 | 84 | jRemove.addActionListener(new java.awt.event.ActionListener() { |
| 98 | 85 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 99 | 86 | jRemoveActionPerformed(evt); |
| 100 | 87 | } |
| 101 | 88 | }); |
| 102 | - |
|
| 103 | 89 | jButton2.setText("Ok"); |
| 104 | 90 | jButton2.addActionListener(new java.awt.event.ActionListener() { |
| 105 | 91 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 106 | 92 | jButton2ActionPerformed(evt); |
| 107 | 93 | } |
| 108 | 94 | }); |
| 109 | - |
|
| 110 | 95 | jCompetitorList.setModel(new javax.swing.AbstractListModel<Competitor>() { |
| 111 | 96 | Competitor[] competitors = { new CompetitorWithoutID("Item 1", "DEU", "Item 1"), |
| 112 | 97 | new CompetitorWithoutID("Item 2", "DEU", "Item 2"), |
| ... | ... | @@ -117,7 +102,6 @@ public class EditSTL extends javax.swing.JDialog { |
| 117 | 102 | public Competitor getElementAt(int i) { return competitors[i]; } |
| 118 | 103 | }); |
| 119 | 104 | jScrollPane1.setViewportView(jCompetitorList); |
| 120 | - |
|
| 121 | 105 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); |
| 122 | 106 | getContentPane().setLayout(layout); |
| 123 | 107 | layout.setHorizontalGroup( |
java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/ui/EditTMD.java
| ... | ... | @@ -54,9 +54,7 @@ public class EditTMD extends javax.swing.JDialog { |
| 54 | 54 | */ |
| 55 | 55 | |
| 56 | 56 | // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| 57 | - @SuppressWarnings("serial") |
|
| 58 | 57 | private void initComponents() { |
| 59 | - |
|
| 60 | 58 | jLabel1 = new javax.swing.JLabel(); |
| 61 | 59 | jRaceId = new javax.swing.JTextField(); |
| 62 | 60 | jLabel2 = new javax.swing.JLabel(); |
| ... | ... | @@ -73,50 +71,35 @@ public class EditTMD extends javax.swing.JDialog { |
| 73 | 71 | jButton3 = new javax.swing.JButton(); |
| 74 | 72 | jScrollPane1 = new javax.swing.JScrollPane(); |
| 75 | 73 | jTmdData = new javax.swing.JList<TimingDataElement>(); |
| 76 | - |
|
| 77 | 74 | setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); |
| 78 | - |
|
| 79 | 75 | jLabel1.setText("Race ID:"); |
| 80 | - |
|
| 81 | 76 | jRaceId.setText("jTextField1"); |
| 82 | - |
|
| 83 | 77 | jLabel2.setText("Sail number:"); |
| 84 | - |
|
| 85 | 78 | jSailNumber.setText("jTextField2"); |
| 86 | - |
|
| 87 | 79 | jLabel3.setText("Mark index:"); |
| 88 | - |
|
| 89 | 80 | jMarkIndex.setText("1"); |
| 90 | - |
|
| 91 | 81 | jLabel4.setText("Rank:"); |
| 92 | - |
|
| 93 | 82 | jRank.setText("1"); |
| 94 | - |
|
| 95 | 83 | jLabel5.setText("Time since start:"); |
| 96 | - |
|
| 97 | 84 | jTimeSinceStart.setText("00:12:14"); |
| 98 | - |
|
| 99 | 85 | jButton1.setText("Remove"); |
| 100 | 86 | jButton1.addActionListener(new java.awt.event.ActionListener() { |
| 101 | 87 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 102 | 88 | jButton1ActionPerformed(evt); |
| 103 | 89 | } |
| 104 | 90 | }); |
| 105 | - |
|
| 106 | 91 | jButton2.setText("Add"); |
| 107 | 92 | jButton2.addActionListener(new java.awt.event.ActionListener() { |
| 108 | 93 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 109 | 94 | jButton2ActionPerformed(evt); |
| 110 | 95 | } |
| 111 | 96 | }); |
| 112 | - |
|
| 113 | 97 | jButton3.setText("Ok"); |
| 114 | 98 | jButton3.addActionListener(new java.awt.event.ActionListener() { |
| 115 | 99 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 116 | 100 | jButton3ActionPerformed(evt); |
| 117 | 101 | } |
| 118 | 102 | }); |
| 119 | - |
|
| 120 | 103 | jTmdData.setModel(new javax.swing.AbstractListModel<TimingDataElement>() { |
| 121 | 104 | TimingDataElement[] strings = { new TimingDataElement(1, 1, new Date()), |
| 122 | 105 | new TimingDataElement(2, 2, new Date()), |
| ... | ... | @@ -127,7 +110,6 @@ public class EditTMD extends javax.swing.JDialog { |
| 127 | 110 | public TimingDataElement getElementAt(int i) { return strings[i]; } |
| 128 | 111 | }); |
| 129 | 112 | jScrollPane1.setViewportView(jTmdData); |
| 130 | - |
|
| 131 | 113 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); |
| 132 | 114 | getContentPane().setLayout(layout); |
| 133 | 115 | layout.setHorizontalGroup( |
java/com.sap.sailing.domain.swisstimingadapter.test/src/com/sap/sailing/domain/swisstimingadapter/test/ui/SwissTimingRaceEditor.java
| ... | ... | @@ -70,10 +70,8 @@ public class SwissTimingRaceEditor extends javax.swing.JFrame { |
| 70 | 70 | * WARNING: Do NOT modify this code. The content of this method is |
| 71 | 71 | * always regenerated by the Form Editor. |
| 72 | 72 | */ |
| 73 | - @SuppressWarnings({ "serial" }) |
|
| 74 | 73 | // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents |
| 75 | 74 | private void initComponents() { |
| 76 | - |
|
| 77 | 75 | jScrollPane1 = new javax.swing.JScrollPane(); |
| 78 | 76 | jCommandList = new javax.swing.JList<Object>(); |
| 79 | 77 | jAdd = new javax.swing.JButton(); |
| ... | ... | @@ -86,54 +84,45 @@ public class SwissTimingRaceEditor extends javax.swing.JFrame { |
| 86 | 84 | jImport = new javax.swing.JMenuItem(); |
| 87 | 85 | jExport = new javax.swing.JMenuItem(); |
| 88 | 86 | jMenuItem3 = new javax.swing.JMenuItem(); |
| 89 | - |
|
| 90 | 87 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); |
| 91 | 88 | setTitle("SwissTiming-Sample-Race Editor"); |
| 92 | - |
|
| 93 | 89 | jCommandList.setModel(new javax.swing.AbstractListModel<Object>() { |
| 94 | 90 | String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; |
| 95 | 91 | public int getSize() { return strings.length; } |
| 96 | 92 | public Object getElementAt(int i) { return strings[i]; } |
| 97 | 93 | }); |
| 98 | 94 | jScrollPane1.setViewportView(jCommandList); |
| 99 | - |
|
| 100 | 95 | jAdd.setText("Add"); |
| 101 | 96 | jAdd.addActionListener(new java.awt.event.ActionListener() { |
| 102 | 97 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 103 | 98 | jAddActionPerformed(evt); |
| 104 | 99 | } |
| 105 | 100 | }); |
| 106 | - |
|
| 107 | 101 | jRemove.setText("Remove"); |
| 108 | 102 | jRemove.addActionListener(new java.awt.event.ActionListener() { |
| 109 | 103 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 110 | 104 | jRemoveActionPerformed(evt); |
| 111 | 105 | } |
| 112 | 106 | }); |
| 113 | - |
|
| 114 | 107 | jEdit.setText("Edit"); |
| 115 | 108 | jEdit.addActionListener(new java.awt.event.ActionListener() { |
| 116 | 109 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 117 | 110 | jEditActionPerformed(evt); |
| 118 | 111 | } |
| 119 | 112 | }); |
| 120 | - |
|
| 121 | 113 | jMoveUp.setText("Up"); |
| 122 | 114 | jMoveUp.addActionListener(new java.awt.event.ActionListener() { |
| 123 | 115 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 124 | 116 | jMoveUpActionPerformed(evt); |
| 125 | 117 | } |
| 126 | 118 | }); |
| 127 | - |
|
| 128 | 119 | jMoveDown.setText("Down"); |
| 129 | 120 | jMoveDown.addActionListener(new java.awt.event.ActionListener() { |
| 130 | 121 | public void actionPerformed(java.awt.event.ActionEvent evt) { |
| 131 | 122 | jMoveDownActionPerformed(evt); |
| 132 | 123 | } |
| 133 | 124 | }); |
| 134 | - |
|
| 135 | 125 | jMenu1.setText("File"); |
| 136 | - |
|
| 137 | 126 | jImport.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, java.awt.event.InputEvent.CTRL_DOWN_MASK)); |
| 138 | 127 | jImport.setText("Import"); |
| 139 | 128 | jImport.addActionListener(new java.awt.event.ActionListener() { |
| ... | ... | @@ -142,7 +131,6 @@ public class SwissTimingRaceEditor extends javax.swing.JFrame { |
| 142 | 131 | } |
| 143 | 132 | }); |
| 144 | 133 | jMenu1.add(jImport); |
| 145 | - |
|
| 146 | 134 | jExport.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_DOWN_MASK)); |
| 147 | 135 | jExport.setText("Export"); |
| 148 | 136 | jExport.addActionListener(new java.awt.event.ActionListener() { |
| ... | ... | @@ -151,7 +139,6 @@ public class SwissTimingRaceEditor extends javax.swing.JFrame { |
| 151 | 139 | } |
| 152 | 140 | }); |
| 153 | 141 | jMenu1.add(jExport); |
| 154 | - |
|
| 155 | 142 | jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ESCAPE, 0)); |
| 156 | 143 | jMenuItem3.setText("Exit"); |
| 157 | 144 | jMenuItem3.addActionListener(new java.awt.event.ActionListener() { |
| ... | ... | @@ -160,11 +147,8 @@ public class SwissTimingRaceEditor extends javax.swing.JFrame { |
| 160 | 147 | } |
| 161 | 148 | }); |
| 162 | 149 | jMenu1.add(jMenuItem3); |
| 163 | - |
|
| 164 | 150 | jMenuBar1.add(jMenu1); |
| 165 | - |
|
| 166 | 151 | setJMenuBar(jMenuBar1); |
| 167 | - |
|
| 168 | 152 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); |
| 169 | 153 | getContentPane().setLayout(layout); |
| 170 | 154 | layout.setHorizontalGroup( |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/TrackTest.java
| ... | ... | @@ -156,7 +156,6 @@ public class TrackTest { |
| 156 | 156 | * {@link Timed} objects in ascending order, this method compares those results to the ordinary explicit calls |
| 157 | 157 | * to {@link GPSFixTrack#getEstimatedPosition(TimePoint, boolean)}. |
| 158 | 158 | */ |
| 159 | - @SuppressWarnings("serial") |
|
| 160 | 159 | @Test |
| 161 | 160 | public void testGetEstimatedPositionSingleVsIteratedWithSmallerSteps() { |
| 162 | 161 | TimePoint start = gpsFix1.getTimePoint().minus((gpsFix5.getTimePoint().asMillis()-gpsFix1.getTimePoint().asMillis())/2); |
| ... | ... | @@ -170,7 +169,6 @@ public class TrackTest { |
| 170 | 169 | assertEqualEstimatedPositionsSingleVsIterated(timeds, /* extrapolate */ false); |
| 171 | 170 | } |
| 172 | 171 | |
| 173 | - @SuppressWarnings("serial") |
|
| 174 | 172 | @Test |
| 175 | 173 | public void testGetEstimatedPositionSingleVsIteratedWithLargerSteps() { |
| 176 | 174 | TimePoint start = gpsFix1.getTimePoint().minus((gpsFix5.getTimePoint().asMillis()-gpsFix1.getTimePoint().asMillis())/2); |
java/com.sap.sailing.gwt.ui/Home.css
| ... | ... | @@ -1 +1 @@ |
| 1 | -/* Not used yet because all CssResources are comming from the design templates. */ |
|
| 1 | +/* Not used yet because all CssResources are coming from the design templates. */ |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/events/TabletAndDesktopEventsView.java
| ... | ... | @@ -14,6 +14,7 @@ import com.sap.sailing.gwt.home.shared.places.start.StartPlace; |
| 14 | 14 | import com.sap.sailing.gwt.ui.client.StringMessages; |
| 15 | 15 | import com.sap.sse.gwt.client.breadcrumb.BreadcrumbPane; |
| 16 | 16 | import com.sap.sse.gwt.client.media.TakedownNoticeService; |
| 17 | +import com.sap.sse.gwt.resources.CommonControlsCSS; |
|
| 17 | 18 | |
| 18 | 19 | public class TabletAndDesktopEventsView extends AbstractEventsView { |
| 19 | 20 | private static EventsPageViewUiBinder uiBinder = GWT.create(EventsPageViewUiBinder.class); |
| ... | ... | @@ -33,9 +34,7 @@ public class TabletAndDesktopEventsView extends AbstractEventsView { |
| 33 | 34 | this.navigator = navigator; |
| 34 | 35 | recentEventsWidget = new EventsOverviewRecent(navigator); |
| 35 | 36 | upcomingEventsWidget = new EventsOverviewUpcoming(navigator); |
| 36 | - |
|
| 37 | 37 | initWidget(uiBinder.createAndBindUi(this)); |
| 38 | - |
|
| 39 | 38 | initBreadCrumbs(); |
| 40 | 39 | } |
| 41 | 40 | |
| ... | ... | @@ -57,6 +56,12 @@ public class TabletAndDesktopEventsView extends AbstractEventsView { |
| 57 | 56 | }); |
| 58 | 57 | } |
| 59 | 58 | |
| 59 | + @Override |
|
| 60 | + protected void onLoad() { |
|
| 61 | + super.onLoad(); |
|
| 62 | + CommonControlsCSS.ensureInjected(); |
|
| 63 | + } |
|
| 64 | + |
|
| 60 | 65 | @Override |
| 61 | 66 | protected void updateEventsUI(TakedownNoticeService takedownNoticeService) { |
| 62 | 67 | recentEventsWidget.updateEvents(eventListView.getRecentEvents(), takedownNoticeService); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/whatsnew/resources/SailingAnalyticsNotes.html
| ... | ... | @@ -13,6 +13,10 @@ |
| 13 | 13 | <li>Bug fix: when a split-fleet series had results only entered manually as score |
| 14 | 14 | corrections, the progress bars for the series were not shown properly. All |
| 15 | 15 | fleets would be considered finished although some may not have seen results.</li> |
| 16 | + <li>The source code of the Sailing Analytics including its companion apps (Race Manager App, |
|
| 17 | + Buoy Pinger App, Sail Insight) has been published under the Apache 2.0 license on |
|
| 18 | + GitHub. See <a href="https://github.com/SAP/sailing-analytics">https://github.com/SAP/sailing-analytics</a>. |
|
| 19 | + Get engaged!</li> |
|
| 16 | 20 | </ul> |
| 17 | 21 | <h5 class="articleSubheadline">September 2025</h5> |
| 18 | 22 | <ul class="bulletList"> |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/MobileEntryPoint.java
| ... | ... | @@ -35,12 +35,9 @@ public class MobileEntryPoint extends AbstractMvpEntryPoint<StringMessages, Mobi |
| 35 | 35 | @Override |
| 36 | 36 | public void doOnModuleLoad() { |
| 37 | 37 | Document.get().getBody().addClassName(SharedResources.INSTANCE.mainCss().mobile()); |
| 38 | - |
|
| 39 | 38 | CommonControlsCSS.ensureInjected(); |
| 40 | - |
|
| 41 | 39 | ServerConfigurationServiceAsync serverConfigService = GWT.create(ServerConfigurationService.class); |
| 42 | 40 | EntryPointHelper.registerASyncService((ServiceDefTarget) serverConfigService, RemoteServiceMappingConstants.serverConfigurationServiceRemotePath); |
| 43 | - |
|
| 44 | 41 | serverConfigService.isStandaloneServer(new AsyncCallback<Boolean>() { |
| 45 | 42 | @Override |
| 46 | 43 | public void onSuccess(Boolean result) { |
java/com.sap.sailing.server.trackfiles.test/src/com/sap/sailing/server/trackfiles/test/JumpyTrackSmootheningTest.java
| ... | ... | @@ -199,8 +199,9 @@ public class JumpyTrackSmootheningTest { |
| 199 | 199 | assertNotNull(markPassings); |
| 200 | 200 | assertEquals(13, markPassings.size()); |
| 201 | 201 | } |
| 202 | - assertTrue(durationForAdjustedTrack.times(8).compareTo(durationForOriginalTrack) < 0, |
|
| 203 | - "Expected duration for mark passing analysis on adjusted track to be at least eight times less than for original track"); |
|
| 202 | + assertTrue(durationForAdjustedTrack.times(2).compareTo(durationForOriginalTrack) < 0, |
|
| 203 | + "Expected duration for mark passing analysis on adjusted track to be at least two times less than for original track: "+ |
|
| 204 | + durationForAdjustedTrack+" vs. "+durationForOriginalTrack); |
|
| 204 | 205 | } |
| 205 | 206 | |
| 206 | 207 | private DynamicGPSFixTrack<Competitor, GPSFixMoving> readTrack(String filename) throws Exception { |
| ... | ... | @@ -227,7 +228,8 @@ public class JumpyTrackSmootheningTest { |
| 227 | 228 | } |
| 228 | 229 | |
| 229 | 230 | /** |
| 230 | - * Simulates the "Oak cliff DH Distance Race" R1 with a single competitor, Gallagher / Zelenka, sail number "1" with |
|
| 231 | + * Simulates the "Oak cliff DH Distance Race" R1 (see https://my.sapsailing.com/gwt/RaceBoard.html?regattaName=Oak+cliff+DH+Distance+Race&raceName=R1&leaderboardName=Oak+cliff+DH+Distance+Race&leaderboardGroupId=a3902560-6bfa-43be-85e1-2b82a4963416&eventId=bf48a59d-f2af-47b6-a2f7-a5b78b22b9f2) |
|
| 232 | + * with a single competitor, Gallagher / Zelenka, sail number "1" with |
|
| 231 | 233 | * the marks pinged statically to establish the course. The track of Gallagher / Zelenka is provided as a track of |
| 232 | 234 | * their GPS positions. This could be the raw track, or it may be a filtered variant of the track with outliers |
| 233 | 235 | * removed or adjusted.<p> |
| ... | ... | @@ -287,7 +289,7 @@ public class JumpyTrackSmootheningTest { |
| 287 | 289 | addFixedMarkPassingToRaceLog("2020-10-14T17:29:36Z", gallagherZelenka, 2, raceLog); |
| 288 | 290 | addFixedMarkPassingToRaceLog("2020-10-14T17:36:42Z", gallagherZelenka, 3, raceLog); |
| 289 | 291 | addFixedMarkPassingToRaceLog("2020-10-14T18:21:38Z", gallagherZelenka, 4, raceLog); |
| 290 | - trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0.0)); |
|
| 292 | + trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.LOADING, 0.0)); // suspends mark passing calculator |
|
| 291 | 293 | final DynamicGPSFixTrack<Competitor, GPSFixMoving> competitorTrackInRace = trackedRace.getTrack(gallagherZelenka); |
| 292 | 294 | // TODO switch race into suspended mode to avoid updates during mass fix insertion: |
| 293 | 295 | competitorTrack.lockForRead(); |
| ... | ... | @@ -298,8 +300,12 @@ public class JumpyTrackSmootheningTest { |
| 298 | 300 | } finally { |
| 299 | 301 | competitorTrack.unlockAfterRead(); |
| 300 | 302 | } |
| 301 | - trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1.0)); |
|
| 302 | - // TODO resume race |
|
| 303 | + trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.TRACKING, 1.0)); // resumes mark passing calculator |
|
| 304 | + // FIXME is it possible that MarkPassingCalculator.Listen has applied only a subset of the changes from its queue when this method returns? |
|
| 305 | + // It scoops up a few events from the queue under the MPC write lock and collects the changes in various collections, but doesn't re-calculate while suspended; |
|
| 306 | + // When the lock is released prior to fetching the next set of events from the queue, the test case calling this method may call getMarkPassings(..., true) |
|
| 307 | + // and obtain the read lock, keeping the Listen thread from applying the next round of updates. Yes, the getMarkPassings(...) call may return something, |
|
| 308 | + // but that may be the result of only applying a subset of the changes, with other changes still in the queue... |
|
| 303 | 309 | return trackedRace; |
| 304 | 310 | } |
| 305 | 311 |
java/com.sap.sailing.www/release_notes_admin.html
| ... | ... | @@ -45,6 +45,10 @@ |
| 45 | 45 | <li><tt>GEONAMES_ORG_USERNAMES</tt> for <tt>geonames.org.usernames</tt></li> |
| 46 | 46 | </ul> |
| 47 | 47 | If the system property is set, it takes precedence over the environment variable.</li> |
| 48 | + <li>The source code of the Sailing Analytics including its companion apps (Race Manager App, |
|
| 49 | + Buoy Pinger App, Sail Insight) has been published under the Apache 2.0 license on |
|
| 50 | + GitHub. See <a href="https://github.com/SAP/sailing-analytics">https://github.com/SAP/sailing-analytics</a>. |
|
| 51 | + Get engaged!</li> |
|
| 48 | 52 | </ul> |
| 49 | 53 | <h2 class="articleSubheadline">September 2025</h2> |
| 50 | 54 | <ul class="bulletList"> |
java/com.sap.sailing.xrr.resultimport/META-INF/MANIFEST.MF
| ... | ... | @@ -24,5 +24,6 @@ Require-Bundle: com.sap.sailing.domain, |
| 24 | 24 | com.sap.sse.common, |
| 25 | 25 | com.sun.xml.bind.jaxb-impl;bundle-version="2.3.0", |
| 26 | 26 | com.sap.sailing.domain.shared.android, |
| 27 | - com.sap.sse |
|
| 27 | + com.sap.sse, |
|
| 28 | + com.sap.sse.security.common |
|
| 28 | 29 | Bundle-Activator: com.sap.sailing.xrr.resultimport.impl.Activator |
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/useragent/UserAgentCheckerImpl.java
| ... | ... | @@ -9,7 +9,6 @@ public class UserAgentCheckerImpl implements UserAgentChecker { |
| 9 | 9 | /** |
| 10 | 10 | * Version numbers indicate minimum required browser (20 = at least this version) |
| 11 | 11 | */ |
| 12 | - @SuppressWarnings("serial") |
|
| 13 | 12 | private static final HashMap<AgentTypes, Integer> MINIMUM_SUPPORTED_AGENTS = new HashMap<AgentTypes, Integer>() { |
| 14 | 13 | { |
| 15 | 14 | put(AgentTypes.MSIE, 9); |
| ... | ... | @@ -17,7 +16,6 @@ public class UserAgentCheckerImpl implements UserAgentChecker { |
| 17 | 16 | put(AgentTypes.OPERA, 10); |
| 18 | 17 | put(AgentTypes.FIREFOX, 10); |
| 19 | 18 | put(AgentTypes.CHROME, 20); |
| 20 | - |
|
| 21 | 19 | } |
| 22 | 20 | }; |
| 23 | 21 |