Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
34f6b53
IONOS(build): update build artifact pipeline to restore apps from cac…
printminion-co Feb 9, 2026
59edc37
IONOS(build): update upload condition to include manual workflow_disp…
printminion-co Feb 9, 2026
ad69668
Update .github/workflows/build-artifact.yml
printminion-co Feb 10, 2026
c5a5589
IONOS(config): update submodule bacda90 (feat(update-user-email): add…
github-actions[bot] Feb 12, 2026
9e2d2ca
IONOS(activity): Switch activity app to IONOS fork
bromiesTM Feb 5, 2026
ddba8e7
IONOS(copilot): eductate copilot on recurring workflow docs
bromiesTM Feb 6, 2026
b898e08
IONOS(activity): update submodule (delegate settings)
bromiesTM Feb 6, 2026
568605b
IONOS(config): update submodule (add delegated activity settings)
bromiesTM Feb 6, 2026
b92d2a6
IONOS(files_pdfviewer): add submodule v31.0.13 (21125af)
Arsalanulhaq Feb 11, 2026
60766e5
IONOS(config): update submodule bdfd74f (build: enable files_pdfviewe…
github-actions[bot] Feb 12, 2026
863dcc2
IONOS(config): update submodule (add flag to hide dev notice)
bromiesTM Feb 11, 2026
c6930a4
IONOS(Settings): hide footer depending on config flag
bromiesTM Feb 11, 2026
49051cf
IONOS(bruteforcesettings): add new submodule
bromiesTM Feb 11, 2026
77af07b
IONOS(bruteforcesettings): update submodule (delegate settings)
bromiesTM Feb 11, 2026
b4e9929
IONOS(config): update submodule (delegate bruteforcesettings)
bromiesTM Feb 11, 2026
8557e68
IONOS(config): update submodule 30be705 (feat(configure): delegate us…
github-actions[bot] Feb 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ The development container provides several convenience features for development:
* Pay attention to the IONOS-specific scripts and configurations when working on related features.
* Use the `IONOS/configure.sh` script for most configuration tasks rather than manual OCC commands.
* Before committing any changes, make sure to run the relevant tests and linters.
* **Recurring Tasks Documentation:** For common development tasks (e.g., delegating settings to admin, adding apps, etc.), check `../<tools-dir>/docs/recurring-tasks/` for step-by-step guides.

## Code Organization & Structure

Expand Down
204 changes: 108 additions & 96 deletions .github/workflows/build-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,6 @@ jobs:
fetch-depth: 1

- name: Setup JFrog CLI
if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true'
uses: jfrog/setup-jfrog-cli@7c95feb32008765e1b4e626b078dfd897c4340ad # v4.4.1
env:
JF_URL: ${{ secrets.JF_ARTIFACTORY_URL }}
Expand All @@ -490,29 +489,111 @@ jobs:
# Ping the server
jf rt ping

- name: Restore cached apps
if: needs.prepare-matrix.outputs.has_apps_to_restore == 'true'
- name: Restore all apps from cache and JFrog
run: |
set -e
set -euo pipefail

# Restore apps that are in cache (from apps_to_restore)
if [ "${{ needs.prepare-matrix.outputs.has_apps_to_restore }}" == "true" ]; then
echo "📦 Restoring cached apps..."
APPS_TO_RESTORE='${{ needs.prepare-matrix.outputs.apps_to_restore }}'

# Process each app in the restore list
echo "$APPS_TO_RESTORE" | jq -c '.[]' | while read -r app_json; do
APP_NAME=$(echo "$app_json" | jq -r '.name')
APP_SHA=$(echo "$app_json" | jq -r '.sha')
APP_PATH=$(echo "$app_json" | jq -r '.path')
SOURCE=$(echo "$app_json" | jq -r '.source')

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Restoring: $APP_NAME (source: $SOURCE)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

if [ "$SOURCE" == "jfrog" ]; then
# Restore from JFrog
JFROG_PATH=$(echo "$app_json" | jq -r '.jfrog_path')
ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz"

echo "📥 Downloading from JFrog: $JFROG_PATH"

if jf rt download "$JFROG_PATH" "$ARCHIVE_NAME" --flat=true; then
echo "✅ Downloaded successfully"
echo "Extracting to $APP_PATH..."
mkdir -p "$(dirname "$APP_PATH")"
tar -xzf "$ARCHIVE_NAME" -C "$(dirname "$APP_PATH")"

if [ -d "$APP_PATH" ] && [ -f "$APP_PATH/appinfo/info.xml" ]; then
echo "✅ Restored $APP_NAME from JFrog"
else
echo "❌ Failed to extract or validate $APP_NAME"
exit 1
fi

rm -f "$ARCHIVE_NAME"
else
echo "❌ Failed to download from JFrog"
exit 1
fi

echo "📦 Restoring cached apps..."
APPS_TO_RESTORE='${{ needs.prepare-matrix.outputs.apps_to_restore }}'
elif [ "$SOURCE" == "github-cache" ]; then
# Restore from GitHub cache
CACHE_KEY=$(echo "$app_json" | jq -r '.cache_key')

# Process each app in the restore list
echo "$APPS_TO_RESTORE" | jq -c '.[]' | while read -r app_json; do
APP_NAME=$(echo "$app_json" | jq -r '.name')
APP_SHA=$(echo "$app_json" | jq -r '.sha')
APP_PATH=$(echo "$app_json" | jq -r '.path')
SOURCE=$(echo "$app_json" | jq -r '.source')
echo "💾 Restoring from GitHub cache: $CACHE_KEY"

# Use actions/cache/restore in a way that works in a script context
# We need to use gh CLI to restore the cache
if gh cache restore "$CACHE_KEY" --key "$CACHE_KEY"; then
echo "✅ Restored $APP_NAME from GitHub cache"

# Validate restoration
if [ ! -d "$APP_PATH" ] || [ ! -f "$APP_PATH/appinfo/info.xml" ]; then
echo "❌ Validation failed for $APP_NAME"
exit 1
fi
else
echo "❌ Failed to restore from GitHub cache"
exit 1
fi
else
echo "❌ Unknown source: $SOURCE"
exit 1
fi
done

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Restoring: $APP_NAME (source: $SOURCE)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ All cached apps restored successfully"
fi

# Also restore newly built apps from JFrog (from apps_to_build)
if [ "${{ needs.prepare-matrix.outputs.has_apps_to_build }}" == "true" ]; then
echo ""
echo "📦 Restoring newly built apps from JFrog..."
APPS_TO_BUILD='${{ needs.prepare-matrix.outputs.apps_to_build }}'
FULL_MATRIX='${{ needs.prepare-matrix.outputs.external_apps_matrix }}'
EFFECTIVE_CACHE_VERSION="${{ needs.prepare-matrix.outputs.effective_cache_version }}"

# Process each app in the build list
echo "$APPS_TO_BUILD" | jq -c '.[]' | while read -r app_json; do
APP_NAME=$(echo "$app_json" | jq -r '.name')
APP_SHA=$(echo "$app_json" | jq -r '.sha')

# Get app path from full matrix
APP_PATH=$(echo "$FULL_MATRIX" | jq -r --arg name "$APP_NAME" '.[] | select(.name == $name) | .path')

if [ "$SOURCE" == "jfrog" ]; then
# Restore from JFrog
JFROG_PATH=$(echo "$app_json" | jq -r '.jfrog_path')
if [ -z "$APP_PATH" ] || [ "$APP_PATH" == "null" ]; then
echo "❌ Could not find path for $APP_NAME in matrix"
exit 1
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Restoring newly built: $APP_NAME"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# Construct JFrog path matching what build-external-apps uploaded
JFROG_PATH="${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/apps/${EFFECTIVE_CACHE_VERSION}/${APP_NAME}/${APP_NAME}-${APP_SHA}.tar.gz"
ARCHIVE_NAME="${APP_NAME}-${APP_SHA}.tar.gz"

echo "📥 Downloading from JFrog: $JFROG_PATH"
Expand All @@ -535,88 +616,19 @@ jobs:
echo "❌ Failed to download from JFrog"
exit 1
fi
done

elif [ "$SOURCE" == "github-cache" ]; then
# Restore from GitHub cache
CACHE_KEY=$(echo "$app_json" | jq -r '.cache_key')

echo "💾 Restoring from GitHub cache: $CACHE_KEY"

# Use actions/cache/restore in a way that works in a script context
# We need to use gh CLI to restore the cache
if gh cache restore "$CACHE_KEY" --key "$CACHE_KEY"; then
echo "✅ Restored $APP_NAME from GitHub cache"

# Validate restoration
if [ ! -d "$APP_PATH" ] || [ ! -f "$APP_PATH/appinfo/info.xml" ]; then
echo "❌ Validation failed for $APP_NAME"
exit 1
fi
else
echo "❌ Failed to restore from GitHub cache"
exit 1
fi
else
echo "❌ Unknown source: $SOURCE"
exit 1
fi
done
echo ""
echo "✅ All newly built apps restored from JFrog successfully"
fi

echo ""
echo "✅ All cached apps restored successfully"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ All apps restored successfully"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
env:
GH_TOKEN: ${{ github.token }}

- name: Download build external apps
uses: actions/download-artifact@v5
with:
pattern: external-app-build-*
path: apps-external/

- name: Reorganize downloaded apps-external artifacts
run: |
cd apps-external/

echo "Initial structure:"
ls -la

# Move contents from external-app-build-* directories to their target directories
for artifact_dir in external-app-build-*; do
if [ -d "$artifact_dir" ]; then
# Extract app name from artifact directory name
app_name=${artifact_dir#external-app-build-}

echo "Processing artifact: $artifact_dir -> $app_name"

# If target directory exists, merge the contents from the artifact directory containing build artifacts
if [ -d "$app_name" ]; then
echo "Target directory $app_name exists, merging contents from $artifact_dir"
# Copy contents from artifact directory to target directory
cp -r "$artifact_dir"/* "$app_name"/
# Remove the now-empty artifact directory
rm -rf "$artifact_dir"
else
# Move the artifact directory to the proper app name
echo "Moving $artifact_dir to $app_name"
mv "$artifact_dir" "$app_name"
fi
fi
done

echo "Reorganization complete. Final structure:"
ls -la

- name: Verify downloaded artifacts structure
run: |
echo "External apps structure:"
ls -la apps-external/
for app_dir in apps-external/*/; do
if [ -d "$app_dir" ]; then
echo "Contents of $app_dir:"
ls -la "$app_dir"
fi
done

- name: Set up node with version from package.json's engines
uses: actions/setup-node@v6
with:
Expand Down Expand Up @@ -698,10 +710,10 @@ jobs:

upload-to-artifactory:
runs-on: self-hosted
# Upload the artifact to the Artifactory repository on PR *OR* on "ionos-dev|ionos-stable|rc/*" branch push defined in the on:push:branches
# Upload the artifact to the Artifactory repository on PR *OR* on "ionos-dev|ionos-stable|rc/*" branch push defined in the on:push:branches *OR* on manual workflow_dispatch
if: |
always() &&
(github.event_name == 'pull_request' || github.ref_name == 'ionos-dev' || github.ref_name == 'ionos-stable' || startsWith(github.ref_name, 'rc/')) &&
(github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' || github.ref_name == 'ionos-dev' || github.ref_name == 'ionos-stable' || startsWith(github.ref_name, 'rc/')) &&
needs.prepare-matrix.result == 'success' &&
(needs.build-external-apps.result == 'success' || needs.build-external-apps.result == 'skipped') &&
needs.build-artifact.result == 'success'
Expand Down
8 changes: 7 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
url = git@github.com:nextcloud/notify_push.git
[submodule "apps-external/activity"]
path = apps-external/activity
url = git@github.com:nextcloud/activity.git
url = git@github.com:IONOS-Productivity/nc-activity.git
[submodule "apps-external/tasks"]
path = apps-external/tasks
url = git@github.com:nextcloud/tasks.git
Expand Down Expand Up @@ -91,3 +91,9 @@
[submodule "apps-external/ncw_tools"]
path = apps-external/ncw_tools
url = git@github.com:IONOS-Productivity/ncw-tools.git
[submodule "apps-external/files_pdfviewer"]
path = apps-external/files_pdfviewer
url = git@github.com:nextcloud/files_pdfviewer.git
[submodule "apps-external/bruteforcesettings"]
path = apps-external/bruteforcesettings
url = git@github.com:IONOS-Productivity/nc-bruteforcesettings.git
2 changes: 1 addition & 1 deletion IONOS
2 changes: 1 addition & 1 deletion apps-external/activity
1 change: 1 addition & 0 deletions apps-external/bruteforcesettings
Submodule bruteforcesettings added at 423a10
1 change: 1 addition & 0 deletions apps-external/files_pdfviewer
Submodule files_pdfviewer added at 21125a
6 changes: 6 additions & 0 deletions apps/settings/lib/Settings/Personal/ServerDevNotice.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use OCP\Settings\ISettings;
use OCP\Support\Subscription\IRegistry;
use OCP\Util;
use OCP\IConfig;

class ServerDevNotice implements ISettings {

Expand All @@ -25,6 +26,7 @@ public function __construct(
private IUserSession $userSession,
private IInitialState $initialState,
private IURLGenerator $urlGenerator,
private IConfig $config,
) {
}

Expand Down Expand Up @@ -62,6 +64,10 @@ public function getSection(): ?string {
return null;
}

if ($this->config->getSystemValueBool('settings.hide-dev-notice')) {
return null;
}

return 'personal-info';
}

Expand Down
Loading