name: Update_Apps # Controls when the workflow will run on: # run at 00:00 UTC every Wednesday schedule: - cron: "0 0 * * 3" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # A workflow run is made up of one or more jobs that can run sequentially or in parallel # this workflow contains 3 jobs that run sequentially: get-latest-app-versions, test-updated-apps, and create-pr # get-latest-app-versions gets the latests app versions and modifies the working directory of the repository with those changes. then it uploads that working directory of the git repository as an artifact for use in later jobs # test-updated-apps runs a matrix of testcases where all updated apps from the first job are tested for successful installation/uninstallation in the working directory of the git repoistory downloaded from the artifact # create-pr then uses the output from get-latest-app-versions and test-updated-apps to finalize a PR where only apps that passed all testcases are updated and any that fail have a descriptive error written in the PR comment jobs: get-latest-app-versions: name: Get Latest App Versions # The type of runner that the job will run on runs-on: ubuntu-latest outputs: UPDATED_APPS: ${{ steps.updated.outputs.UPDATED_APPS }} FAILED_APPS: ${{ steps.failed.outputs.FAILED_APPS }} # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v3 # Runs a set of commands using the runners shell - name: Run app update scripts env: GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} run: | # print user info echo $USER $USERNAME $(id) $(whoami) #source pi-apps functions #export all functions and variables set -a #make DIRECTORY equal to GITHUB_WORKSPACE, for subscripts and api functions DIRECTORY=$GITHUB_WORKSPACE source $GITHUB_WORKSPACE/api #add special functions get_release() { curl -s --header "Authorization: token $GH_PERSONAL_ACCESS_TOKEN" "https://api.github.com/repos/$1/releases/latest" | jq -r '.tag_name' | sed s/^v//g } get_release_raw() { curl -s --header "Authorization: token $GH_PERSONAL_ACCESS_TOKEN" "https://api.github.com/repos/$1/releases/latest" | jq -r '.tag_name' } get_prerelease() { curl -s --header "Authorization: token $GH_PERSONAL_ACCESS_TOKEN" "https://api.github.com/repos/$1/releases" | jq -r 'map(select(.prerelease)) | first | .tag_name' | sed s/^v//g } get_prerelease_raw() { curl -s --header "Authorization: token $GH_PERSONAL_ACCESS_TOKEN" "https://api.github.com/repos/$1/releases" | jq -r 'map(select(.prerelease)) | first | .tag_name' } function validate_url(){ if command wget --timeout=5 -q --spider "$1"; then return 0 else return 1 fi } #stop exporting functions set +a #make sure all update scripts are executable chmod +x $GITHUB_WORKSPACE/.github/workflows/updates/*.sh cd $GITHUB_WORKSPACE apps=( .github/workflows/updates/*.sh ) for app_directory in "${apps[@]}"; do echo #make sure we are still in the main workspace (incase an update script left off elsewhere) cd $GITHUB_WORKSPACE export app_name="$(echo ${app_directory%.*} | sed 's:.*/::')" echo "$app_name" status "Checking $app_name for updates" # move to app folder cd "$GITHUB_WORKSPACE/apps/$app_name" # run app update script "$GITHUB_WORKSPACE/$app_directory" done cd - name: Output updated apps id: updated run: | if test -f /tmp/updated_apps; then sort -u /tmp/updated_apps > /tmp/updated_apps_sorted echo "UPDATED_APPS<> $GITHUB_OUTPUT cat /tmp/updated_apps_sorted >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi - name: Output failed apps id: failed run: | if test -f /tmp/failed_apps; then echo "FAILED_APPS<> $GITHUB_OUTPUT cat /tmp/failed_apps | sed '0~1 a\\' >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT fi - name: Tar GITHUB_WORKSPACE run: | cd ${{ runner.temp }} tar -C $GITHUB_WORKSPACE -cvf GITHUB_WORKSPACE.tar . - name: Upload GITHUB_WORKSPACE Artifact uses: actions/upload-artifact@v3 with: name: GITHUB_WORKSPACE path: ${{ runner.temp }}/GITHUB_WORKSPACE.tar test-updated-apps: runs-on: ubuntu-latest needs: get-latest-app-versions strategy: matrix: include: - os: buster arch: armhf image: https://downloads.raspberrypi.org/raspios_oldstable_armhf/images/raspios_oldstable_armhf-2023-05-03/2023-05-03-raspios-buster-armhf.img.xz cache: yes - os: buster arch: arm64 image: https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2021-05-28/2021-05-07-raspios-buster-arm64.zip cache: yes - os: bullseye arch: armhf image: https://downloads.raspberrypi.org/raspios_armhf/images/raspios_armhf-2023-05-03/2023-05-03-raspios-bullseye-armhf.img.xz cache: yes - os: bullseye arch: arm64 image: https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2023-05-03/2023-05-03-raspios-bullseye-arm64.img.xz cache: yes - os: bookworm arch: arm64 image: RPIOS_BOOKWORM_URL cache: no name: Testing on ${{ matrix.os }} - ${{ matrix.arch }} outputs: FAILED_UPDATE_APPS_buster_armhf: ${{ steps.failed.outputs.FAILED_UPDATE_APPS_buster_armhf || '' }} FAILED_UPDATE_APPS_buster_arm64: ${{ steps.failed.outputs.FAILED_UPDATE_APPS_buster_arm64 || '' }} FAILED_UPDATE_APPS_bullseye_armhf: ${{ steps.failed.outputs.FAILED_UPDATE_APPS_bullseye_armhf || '' }} FAILED_UPDATE_APPS_bullseye_arm64: ${{ steps.failed.outputs.FAILED_UPDATE_APPS_bullseye_arm64 || '' }} FAILED_UPDATE_APPS_bookworm_arm64: ${{ steps.failed.outputs.FAILED_UPDATE_APPS_bookworm_arm64 || '' }} UPDATED_APPS_buster_armhf: ${{ steps.updated.outputs.UPDATED_APPS_buster_armhf || '' }} UPDATED_APPS_buster_arm64: ${{ steps.updated.outputs.UPDATED_APPS_buster_arm64 || '' }} UPDATED_APPS_bullseye_armhf: ${{ steps.updated.outputs.UPDATED_APPS_bullseye_armhf || '' }} UPDATED_APPS_bullseye_arm64: ${{ steps.updated.outputs.UPDATED_APPS_bullseye_arm64 || '' }} UPDATED_APPS_bookworm_arm64: ${{ steps.updated.outputs.UPDATED_APPS_bookworm_arm64 || '' }} steps: # restore GITHUB_WORKSPACE - uses: actions/download-artifact@v3 with: name: GITHUB_WORKSPACE path: ${{ runner.temp }} - name: Extract GITHUB_WORKSPACE run: | cd ${{ runner.temp }} tar xf GITHUB_WORKSPACE.tar -C $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE - name: Replace secret reference with contents if: ${{ matrix.image == 'RPIOS_BOOKWORM_URL' }} run: | image_url=${{ secrets[matrix.image] }} echo "::add-mask::$image_url" echo "image_url=$image_url" >> "$GITHUB_ENV" - name: Replace non-secret reference with contents if: ${{ matrix.image != 'RPIOS_BOOKWORM_URL' }} run: | image_url=${{ matrix.image }} echo "image_url=$image_url" >> "$GITHUB_ENV" - name: Write UPDATED_APPS and FAILED_APPS from OUTPUT of get-latest-app-versions to ENV run: | echo "UPDATED_APPS<> $GITHUB_ENV echo "${{needs.get-latest-app-versions.outputs.UPDATED_APPS}}" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV echo "FAILED_APPS<> $GITHUB_ENV echo "${{needs.get-latest-app-versions.outputs.FAILED_APPS}}" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV - name: Test installing updated apps on ${{ matrix.os }} - ${{ matrix.arch }} uses: theofficialgman/arm-runner-action@v12 with: base_image: ${{ env.image_url }} # bind mount the directory so any changes propogate to outside the chroot bind_mount_repository: yes # give the image more space image_additional_mb: 5000 # disable image caching to not leak the URL on some systems enable_image_caching: ${{ matrix.cache }} # set CPUs to use cpu: cortex-a7:cortex-a72 # use custom /proc/cpuinfo cpu_info: cpuinfo/raspberrypi_4b # user runner name as default path copy_repository_path: /home/runner/pi-apps # export github env back to outside the chroot export_github_env: yes import_github_env: true # set shell to bash shell: /bin/bash commands: | sudo chown runner:docker /home/runner # print user info echo $USER $USERNAME $(id) $(whoami) sudo bash -c 'echo $USER $USERNAME $(id) $(whoami)' # create standard directories mkdir -p $HOME/.local/share/applications $HOME/.local/bin sudo mkdir -p /usr/local/bin /usr/local/share/applications # install pi-apps dependencies sudo apt update sudo apt install -y yad curl wget aria2 lsb-release software-properties-common apt-utils imagemagick bc librsvg2-bin locales shellcheck git wmctrl xdotool x11-utils rsync # runonce-entries is run in the build tester, runonce requires that all api functions be available to subprocess (like is done in the gui script) #for the will_reinstall() and list_intersect() functions set -a #make all functions in the api available to subprocesses #make DIRECTORY equal to GITHUB_WORKSPACE, for subscripts and api functions DIRECTORY=$(pwd) source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api" #Run runonce entries "${DIRECTORY}/etc/runonce-entries" set +a #stop exporting functions cd ${DIRECTORY} # upgrade cmake to 3.20+ from theofficialgman ppa to fix QEMU only issue https://gitlab.kitware.com/cmake/cmake/-/issues/20568 package_is_new_enough cmake 3.20 || debian_ppa_installer "theofficialgman/cmake-bionic" "bionic" "0ACACB5D1E74E484" || exit 1 # store apps changed from last commit to working directory in variable mapfile -t changed_apps < <(git diff --name-only | grep ^apps/ | awk -F '/' '{print $2}' | sort -u) # clean out any app status files rm -rf ./data/status # attempt to install updated apps using manage script loop # if any app fails, add it to the FAILED_INSTALL_APPS or FAILED_UNINSTALL_APPS variable if [[ ${{ matrix.arch }} == armhf ]]; then # skip checking DDNet (due to Rust) if on arm32 under QEMU: https://github.com/rust-lang/cargo/issues/8719 # skip checking Microsoft PowerShell due to QEMU instability with .NET: https://github.com/Botspot/pi-apps/pull/2252#issuecomment-1403043945 # skip WPS Office on 32bit as it requires "64bit" kernel to be detected. QEMU reports an armv7 kernel. WPS Office is still tested on arm64 (which will verify if the deb works and installs correctly) skiplist="DDNet Microsoft PowerShell WPS Office" else # skip checking Microsoft PowerShell due to QEMU instability with .NET: https://github.com/Botspot/pi-apps/pull/2252#issuecomment-1403043945 skiplist="Microsoft PowerShell" fi for app in "${changed_apps[@]}"; do # only attempt install/uninstall if updated app is supported on this architecture scriptname="$(script_name_cpu "$app")" #will be install, install-32, install-64, or package if [ -z "$scriptname" ];then continue fi # skip app if is in the skiplist if echo "$skiplist" | grep -Fxq "$app"; then continue fi ./manage install "$app" || { FAILED_INSTALL_APPS+="$app"$'\n'; UPDATED_APPS=$(echo "$UPDATED_APPS" | sed "/$app/d"); } ./manage uninstall "$app" || { FAILED_UNINSTALL_APPS+="$app"$'\n'; UPDATED_APPS=$(echo "$UPDATED_APPS" | sed "/$app/d"); } done if [ ! -z "$FAILED_INSTALL_APPS" ] || [ ! -z "$FAILED_UNINSTALL_APPS" ]; then echo "FAILED_UPDATE_APPS<> $GITHUB_ENV echo "$FAILED_INSTALL_APPS$FAILED_UNINSTALL_APPS" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV echo "UPDATED_APPS<> $GITHUB_ENV echo "$UPDATED_APPS" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV fi - name: Write FAILED_APPS to OUTPUT id: failed run: | echo "FAILED_UPDATE_APPS_${{ matrix.os }}_${{ matrix.arch }}<> $GITHUB_OUTPUT echo "${{env.FAILED_UPDATE_APPS}}" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Write UPDATED_APPS to OUTPUT id: updated run: | echo "UPDATED_APPS_${{ matrix.os }}_${{ matrix.arch }}<> $GITHUB_OUTPUT echo "${{env.UPDATED_APPS}}" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT create-pr: needs: [get-latest-app-versions,test-updated-apps] runs-on: ubuntu-latest steps: # restore GITHUB_WORKSPACE - uses: actions/download-artifact@v3 with: name: GITHUB_WORKSPACE path: ${{ runner.temp }} - name: Extract GITHUB_WORKSPACE run: | cd ${{ runner.temp }} tar xf GITHUB_WORKSPACE.tar -C $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE - name: Delete artifact uses: geekyeggo/delete-artifact@v2 with: name: GITHUB_WORKSPACE failOnError: false - name: Revert failed apps and generate list run: | ALL_FAILED_APPS="${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_buster_armhf}}"$'\n'"${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_buster_arm64}}"$'\n'"${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bullseye_armhf}}"$'\n'"${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bullseye_arm64}}"$'\n'"${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bookworm_arm64}}" ALL_FAILED_APPS="$(echo "$ALL_FAILED_APPS" | sort -u | awk NF)" echo "ALL_FAILED_APPS<> $GITHUB_ENV echo "$ALL_FAILED_APPS" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV error_string="" IFS=$'\n' for app in $ALL_FAILED_APPS; do git checkout -- "apps/$app" error_string+='![badge-error][badge-error]'" Failed to install $app on " if echo "${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_buster_armhf}}" | grep -Fxq "$app"; then error_string+="buster armhf, " fi if echo "${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_buster_arm64}}" | grep -Fxq "$app"; then error_string+="buster arm64, " fi if echo "${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bullseye_armhf}}" | grep -Fxq "$app"; then error_string+="bullseye armhf, " fi if echo "${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bullseye_arm64}}" | grep -Fxq "$app"; then error_string+="bullseye arm64, " fi if echo "${{needs.test-updated-apps.outputs.FAILED_UPDATE_APPS_bookworm_arm64}}" | grep -Fxq "$app"; then error_string+="bookworm arm64, " fi error_string+="reverting to previous version."$'\n'$'\n' done true echo "ALL_FAILED_APPS_ERROR_STRING<> $GITHUB_ENV echo "$error_string" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV - name: Generate updated apps list run: | list_subtract() { #Outputs a list of apps from stdin, minus the ones that appear in $1 using the UPDATED_APP format # for example, the following two inputs will be a match # - BlockBench-arm64: 4.7.4 -> 4.8.0 # BlockBench # change \n to -\n | change '^' to '- ' grep -ve "$(echo "$1" | sed -z 's/\n/\-\n/g' | sed 's/^/- /g')" true } ALL_UPDATED_APPS="${{needs.test-updated-apps.outputs.UPDATED_APPS_buster_armhf}}"$'\n'"${{needs.test-updated-apps.outputs.UPDATED_APPS_buster_arm64}}"$'\n'"${{needs.test-updated-apps.outputs.UPDATED_APPS_bullseye_armhf}}"$'\n'"${{needs.test-updated-apps.outputs.UPDATED_APPS_bullseye_arm64}}"$'\n'"${{needs.test-updated-apps.outputs.UPDATED_APPS_bookworm_arm64}}" ALL_UPDATED_APPS="$(echo "$ALL_UPDATED_APPS" | sort -u | awk NF)" [ ! -z "$ALL_UPDATED_APPS" ] && ALL_UPDATED_APPS="$(echo "$ALL_UPDATED_APPS" | list_subtract "$ALL_FAILED_APPS")" echo "ALL_UPDATED_APPS<> $GITHUB_ENV echo "$ALL_UPDATED_APPS" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV - name: Create Pull Request uses: peter-evans/create-pull-request@v4 with: author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> commit-message: | Update App Versions, run by GitHub Actions - Apps updated: ${{ env.ALL_UPDATED_APPS }} branch: "auto-app-updates-NOT-FOR-USERS" title: "[AUTO] Update App Versions" body: | [badge-error]: https://github.com/Pi-Apps-Coders/GitHub-Markdown/blob/main/blockquotes/badge/dark-theme/error.svg?raw=true 'Error' [badge-warning]: https://github.com/Pi-Apps-Coders/GitHub-Markdown/blob/main/blockquotes/badge/dark-theme/warning.svg?raw=true 'Warning' [badge-issue]: https://github.com/Pi-Apps-Coders/GitHub-Markdown/blob/main/blockquotes/badge/dark-theme/issue.svg?raw=true 'Issue' [badge-check]: https://github.com/Pi-Apps-Coders/GitHub-Markdown/blob/main/blockquotes/badge/dark-theme/check.svg?raw=true 'Check' [badge-info]: https://github.com/Pi-Apps-Coders/GitHub-Markdown/blob/main/blockquotes/badge/dark-theme/info.svg?raw=true 'Info' Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action. Workflow run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} Apps updated: ``` ${{ env.ALL_UPDATED_APPS }} ``` ${{needs.get-latest-app-versions.outputs.FAILED_APPS}} ${{ env.ALL_FAILED_APPS_ERROR_STRING }}