diff --git a/.github/act/push.json b/.github/act/push.json new file mode 100644 index 0000000..5cc1532 --- /dev/null +++ b/.github/act/push.json @@ -0,0 +1,24 @@ +{ + "ref": "refs/heads/main", + "before": "0000000000000000000000000000000000000000", + "after": "0000000000000000000000000000000000000001", + "forced": false, + "repository": { + "name": "prepare_linux_desktop", + "full_name": "ansible102/prepare_linux_desktop", + "private": false, + "default_branch": "main" + }, + "pusher": { + "name": "mbojko", + "email": "marcinbojko.pl@gmail.com" + }, + "head_commit": { + "id": "0000000000000000000000000000000000000001", + "message": "test push", + "author": { + "name": "mbojko", + "email": "marcinbojko.pl@gmail.com" + } + } +} diff --git a/.github/linters/.yamllint.yml b/.github/linters/.yamllint.yml new file mode 100644 index 0000000..4fe4f3e --- /dev/null +++ b/.github/linters/.yamllint.yml @@ -0,0 +1,14 @@ +--- +extends: default + +rules: + line-length: + max: 160 + level: warning + document-start: disable + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + braces: + min-spaces-inside: 0 + max-spaces-inside: 1 diff --git a/.github/workflows/01_lint_me.yml b/.github/workflows/01_lint_me.yml index 292745c..b7d46e3 100644 --- a/.github/workflows/01_lint_me.yml +++ b/.github/workflows/01_lint_me.yml @@ -1,51 +1,30 @@ name: Super-Linter -# Run this workflow every time a new commit pushed to your repository on: push: - branches: [main, master, test, develop] pull_request: branches: [main, master] workflow_dispatch: permissions: - contents: write - pull-requests: write - packages: write - actions: read - deployments: read - id-token: write - issues: write - discussions: read - pages: read - repository-projects: read - security-events: read - attestations: read # Added this - checks: write # Added this - statuses: write # Added + contents: read + statuses: write + jobs: - # Set the job key. The key is displayed as the job name - # when a job name is not provided super-lint: - # Name the Job name: Lint code base - # Set the type of machine to run on runs-on: ubuntu-latest steps: - # Checks out a copy of your repository on the ubuntu-latest machine - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 - # Runs the Super-Linter action - name: Run Super-Linter - # workaround for superlinter issues - uses: github/super-linter@main + uses: super-linter/super-linter@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0 env: - DEFAULT_BRANCH: ${{ github.ref_name }} + DEFAULT_BRANCH: ${{ github.event.pull_request.base.ref || github.event.repository.default_branch || 'main' }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VALIDATE_ALL_CODEBASE: ${{ github.event_name != 'pull_request' }} - VALIDATE_JSCPD: false - # VALIDATE_ANSIBLE: false - VALIDATE_NATURAL_LANGUAGE: false - # VALIDATE_DOCKERFILE_HADOLINT: false + VALIDATE_ALL_CODEBASE: false + VALIDATE_YAML: true diff --git a/.github/workflows/02_syntax_check.yml b/.github/workflows/02_syntax_check.yml new file mode 100644 index 0000000..313cfe2 --- /dev/null +++ b/.github/workflows/02_syntax_check.yml @@ -0,0 +1,34 @@ +--- +name: Syntax Check + +on: + push: + pull_request: + branches: [main, master] + workflow_dispatch: + +permissions: + contents: read + +jobs: + syntax-check: + name: Ansible syntax check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install dependencies + run: pip install -r molecule/requirements.txt + + - name: Install collections + run: ansible-galaxy collection install -r requirements.yml + + - name: Run molecule syntax + run: molecule syntax diff --git a/.gitignore b/.gitignore index 540b828..6a602c6 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,16 @@ # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) +### act (local GitHub Actions runner) ### +.github/act/*.secrets +.github/act/*.env +.env +.env.* + +### Python ### +__pycache__/ +*.py[cod] + *.retry *.out *.html @@ -54,3 +64,5 @@ */.cache* .cache* .vscode/ +Claude.md +.claude/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e3fc7d..f8984de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,39 @@ # Changelog "prepare_linux_desktop" ansible role +## Version 1.2.0 [2025-12-27] + +- [BUGFIX] fixed `palemoon` repository to use home:stevenpusser instead of home:stevenpusser:palemoon-GTK3 +- [BUGFIX] fixed `palemoon` repository URL to xUbuntu_24.04 (was xUbuntu_23.10) +- [BUGFIX] disabled invalid `helm-stable-debian` repository (Helm installed via HashiCorp repo) +- [BUGFIX] fixed `gping` download filename format (gping_1.20.1_linux_x86_64.tar.gz) +- [DEB] upgraded `ipscan` to version 3.9.3 +- [DEB] upgraded `tabby` to version 1.0.228 +- [DEB] upgraded `minikube` to version 1.37.0 +- [DEB] upgraded `balena-etcher` to version 2.1.4 +- [DEB] upgraded `kube-bench` to version 0.14.1 +- [DEB] upgraded `syft` to version 1.33.0 +- [DEB] upgraded `steampipe` to version 2.2.0 +- [DEB] upgraded `rambox` to version 2.5.2 +- [DEB] upgraded `k9s` to version 0.50.12 +- [DEB] upgraded `sops` to version 3.11.0 +- [DEB] upgraded `atuin` to version 18.10.0 +- [PACKAGES] upgraded `kubeconform` to version 0.7.0 +- [PACKAGES] upgraded `tflint` to version 0.60.1 +- [PACKAGES] upgraded `nerdctl` to version 2.1.1 +- [PACKAGES] upgraded `kustomize` to version 5.8.0 +- [PACKAGES] upgraded `kubent` to stable version 0.7.3 +- [PACKAGES] upgraded `act` to version 0.2.83 +- [PACKAGES] upgraded `eza` to version 0.23.4 +- [PACKAGES] upgraded `polaris` to version 9.6.3 +- [PACKAGES] upgraded `gping` to version 1.20.1 +- [PACKAGES] upgraded `lazydocker` to version 0.24.3 +- [PACKAGES] upgraded `k3s` to version 1.34.2+k3s1 +- [PACKAGES] upgraded `k3d` to version 5.8.3 +- [PACKAGES] upgraded `hadolint` to version 2.14.0 +- [PACKAGES] upgraded `yq` to version 4.49.1 +- [PACKAGES] upgraded `kubeswitch` to version 0.9.3 +- [PACKAGES] upgraded `argocd` to version 2.14.20 + ## Version 1.1.1 [2024-11-17] - [PACKAGES] added `shfmt` -[https://github.com/patrickvane/shfmt](https://github.com/patrickvane/shfmt) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml new file mode 100644 index 0000000..f694cef --- /dev/null +++ b/molecule/default/converge.yml @@ -0,0 +1,8 @@ +--- +- name: Converge + hosts: all + gather_facts: true + roles: + - role: pld + vars: + pld_active_user: "{{ ansible_user_id | default('ci') }}" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml new file mode 100644 index 0000000..835f744 --- /dev/null +++ b/molecule/default/molecule.yml @@ -0,0 +1,27 @@ +--- +dependency: + name: galaxy + options: + requirements-file: requirements.yml + ignore-certs: true + ignore-errors: true + +driver: + name: default + +platforms: + - name: instance + +provisioner: + name: ansible + env: + ANSIBLE_ROLES_PATH: "${MOLECULE_PROJECT_DIRECTORY}/roles" + config_options: + defaults: + interpreter_python: auto_silent + any_errors_fatal: false + playbooks: + converge: converge.yml + +verifier: + name: ansible diff --git a/molecule/proxmox/create.yml b/molecule/proxmox/create.yml new file mode 100644 index 0000000..2f390f0 --- /dev/null +++ b/molecule/proxmox/create.yml @@ -0,0 +1,33 @@ +--- +- name: Create Proxmox snapshots before converge + hosts: localhost + gather_facts: false + vars: + snapshot_name: "molecule-before" + proxmox_api: &proxmox_api + api_host: "{{ lookup('env', 'PROXMOX_HOST') }}" + api_port: "{{ lookup('env', 'PROXMOX_PORT') | int }}" + api_user: "{{ lookup('env', 'PROXMOX_API_USER') }}" + api_token_id: "{{ lookup('env', 'PROXMOX_TOKEN_ID') }}" + api_token_secret: "{{ lookup('env', 'PROXMOX_TOKEN_SECRET') }}" + validate_certs: false + + tasks: + - name: Remove stale molecule snapshot if present + community.proxmox.proxmox_snap: + <<: *proxmox_api + vmid: "{{ item }}" + snapname: "{{ snapshot_name }}" + state: absent + loop: [153, 167] + ignore_errors: true + + - name: Create snapshot + community.proxmox.proxmox_snap: + <<: *proxmox_api + vmid: "{{ item }}" + snapname: "{{ snapshot_name }}" + description: "Created by molecule before converge" + state: present + timeout: 120 + loop: [153, 167] diff --git a/molecule/proxmox/destroy.yml b/molecule/proxmox/destroy.yml new file mode 100644 index 0000000..013a118 --- /dev/null +++ b/molecule/proxmox/destroy.yml @@ -0,0 +1,31 @@ +--- +- name: Rollback Proxmox snapshots after converge + hosts: localhost + gather_facts: false + vars: + snapshot_name: "molecule-before" + proxmox_api: &proxmox_api + api_host: "{{ lookup('env', 'PROXMOX_HOST') }}" + api_port: "{{ lookup('env', 'PROXMOX_PORT') | int }}" + api_user: "{{ lookup('env', 'PROXMOX_API_USER') }}" + api_token_id: "{{ lookup('env', 'PROXMOX_TOKEN_ID') }}" + api_token_secret: "{{ lookup('env', 'PROXMOX_TOKEN_SECRET') }}" + validate_certs: false + + tasks: + - name: Rollback to snapshot + community.proxmox.proxmox_snap: + <<: *proxmox_api + vmid: "{{ item }}" + snapname: "{{ snapshot_name }}" + state: rollback + timeout: 120 + loop: [153, 167] + + - name: Delete snapshot + community.proxmox.proxmox_snap: + <<: *proxmox_api + vmid: "{{ item }}" + snapname: "{{ snapshot_name }}" + state: absent + loop: [153, 167] diff --git a/molecule/proxmox/molecule.yml b/molecule/proxmox/molecule.yml new file mode 100644 index 0000000..2ce2354 --- /dev/null +++ b/molecule/proxmox/molecule.yml @@ -0,0 +1,46 @@ +--- +dependency: + name: galaxy + options: + requirements-file: requirements.yml + ignore-certs: true + ignore-errors: true + +driver: + name: default + +platforms: + - name: mint22-0 + - name: mint22-2 + +provisioner: + name: ansible + env: + ANSIBLE_ROLES_PATH: "${MOLECULE_PROJECT_DIRECTORY}/roles" + config_options: + defaults: + interpreter_python: auto_silent + any_errors_fatal: false + host_key_checking: false + connection_options: + ansible_user: "${PROXMOX_VM_USER}" + ansible_password: "${PROXMOX_VM_PASSWORD}" + ansible_become: true + ansible_become_password: "${PROXMOX_VM_PASSWORD}" + inventory: + hosts: + all: + hosts: + mint22-0: + ansible_host: "${PROXMOX_VM_167_HOST}" + proxmox_vmid: 167 + mint22-2: + ansible_host: "${PROXMOX_VM_153_HOST}" + proxmox_vmid: 153 + playbooks: + create: create.yml + destroy: destroy.yml + converge: ../default/converge.yml + +verifier: + name: ansible diff --git a/molecule/requirements.txt b/molecule/requirements.txt new file mode 100644 index 0000000..cc564f6 --- /dev/null +++ b/molecule/requirements.txt @@ -0,0 +1,7 @@ +ansible-core>=2.19 +molecule>=25.7 +molecule-plugins>=25.8 +ansible-lint>=25.12 +yamllint>=1.37 +proxmoxer>=2.0 +requests>=2.31 diff --git a/requirements.yml b/requirements.yml index 61d9e43..9f48284 100644 --- a/requirements.yml +++ b/requirements.yml @@ -3,3 +3,4 @@ collections: - name: ansible.posix - name: community.general - name: community.crypto + - name: community.proxmox diff --git a/roles/pld/handlers/main.yml b/roles/pld/handlers/main.yml index e69de29..73b314f 100644 --- a/roles/pld/handlers/main.yml +++ b/roles/pld/handlers/main.yml @@ -0,0 +1 @@ +--- \ No newline at end of file diff --git a/roles/pld/tasks/install_keys_and_repos.yml b/roles/pld/tasks/install_keys_and_repos.yml index 0b6e856..07d87f4 100644 --- a/roles/pld/tasks/install_keys_and_repos.yml +++ b/roles/pld/tasks/install_keys_and_repos.yml @@ -87,6 +87,25 @@ enabled: "{{ item.enabled | default('true') }}" signed_by: "{{ item.signed_by | default('null') }}" architectures: "{{ item.architectures | default('') }}" + state: "{{ item.state | default('absent') }}" + loop: "{{ pld_deb822_repositories }}" + changed_when: false + tags: + - repositories + - base + - deb822 + +- name: Add basic repositories as deb822 format + ansible.builtin.deb822_repository: + name: "{{ item.name }}" + types: "{{ item.types | default('deb') }}" + suites: "{{ item.suites | default('/') }}" + components: "{{ item.components | default(' ') }}" + uris: "{{ item.uris }}" + enabled: "{{ item.enabled | default('true') }}" + signed_by: "{{ item.signed_by | default('null') }}" + architectures: "{{ item.architectures | default('') }}" + state: present loop: "{{ pld_deb822_repositories }}" register: r_repositories until: r_repositories is success @@ -106,6 +125,27 @@ enabled: "{{ item.enabled | default('true') }}" signed_by: "{{ item.signed_by | default('null') }}" architectures: "{{ item.architectures | default('') }}" + state: "{{ item.state | default('absent') }}" + loop: "{{ custom_repositories }}" + when: custom_repositories is defined and custom_repositories | length > 0 + changed_when: false + tags: + - repositories + - base + - deb822 + - custom + +- name: Add custom repositories as deb822 format + ansible.builtin.deb822_repository: + name: "{{ item.name }}" + types: "{{ item.types | default('deb') }}" + suites: "{{ item.suites | default('/') }}" + components: "{{ item.components | default(' ') }}" + uris: "{{ item.uris }}" + enabled: "{{ item.enabled | default('true') }}" + signed_by: "{{ item.signed_by | default('null') }}" + architectures: "{{ item.architectures | default('') }}" + state: present register: r_custom_repositories until: r_custom_repositories is success loop: "{{ custom_repositories }}" diff --git a/roles/pld/tasks/remove_obsolete.yml b/roles/pld/tasks/remove_obsolete.yml index 4e1c9bf..b142cfc 100644 --- a/roles/pld/tasks/remove_obsolete.yml +++ b/roles/pld/tasks/remove_obsolete.yml @@ -16,11 +16,13 @@ - base - obsolete # Tasks removes all files from `pld_files_remove` list -- name: "Remove_obsolete_files_from_variables_file: {{ item.path }}" +- name: "Remove obsolete files from variables file" ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ pld_files_remove | default([]) }}" + loop_control: + label: "{{ item.path }}" retries: "{{ pld_retries_count }}" delay: "{{ pld_delay_time }}" register: r_files_remove diff --git a/roles/pld/vars/shared.yml b/roles/pld/vars/shared.yml index 0485c38..feeb996 100644 --- a/roles/pld/vars/shared.yml +++ b/roles/pld/vars/shared.yml @@ -17,9 +17,9 @@ pld_deb822_repositories: suites: "/" components: [] uris: - - "http://download.opensuse.org/repositories/home:/stevenpusser:/palemoon-GTK3/xUbuntu_23.10/" + - "http://download.opensuse.org/repositories/home:/stevenpusser/xUbuntu_24.04/" enabled: true - signed_by: https://download.opensuse.org/repositories/home:/stevenpusser/xUbuntu_23.10/Release.key + signed_by: https://download.opensuse.org/repositories/home:stevenpusser/xUbuntu_24.04/Release.key - name: azure-cli types: deb suites: "{{ pld_codename }}" @@ -137,15 +137,16 @@ pld_deb822_repositories: enabled: true architectures: amd64 signed_by: https://apt.releases.hashicorp.com/gpg - - name: helm-stable-debian - types: deb - suites: all - components: main - uris: - - "https://baltocdn.com/helm/stable/debian/" - enabled: true - architectures: amd64 - signed_by: https://baltocdn.com/helm/signing.asc + # Note: Helm is installed via HashiCorp repository (see hashicorp repo below) + # - name: helm-stable-debian + # types: deb + # suites: all + # components: main + # uris: + # - "https://baltocdn.com/helm/stable/debian/" + # enabled: true + # architectures: amd64 + # signed_by: https://baltocdn.com/helm/signing.asc - name: trippy types: deb suites: noble @@ -208,7 +209,7 @@ pld_repositories_remove: codename: impish - repo: ppa:libreoffice/ppa filename: libreoffice - - repo: deb [arch=amd64] https://download.opensuse.org/repositories/home:/stevenpusser/xUbuntu_22.04/ / + - repo: deb [arch=amd64] https://wmlive.rumbero.org/repo/pool/main/p/palemoon/ / filename: palemoon - repo: deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ noble main filename: azure-cli @@ -291,7 +292,6 @@ pld_files_remove: - path: /etc/apt/sources.list.d/azure-cli.list - path: /etc/apt/sources.list.d/docker-stable.list - path: /etc/apt/sources.list.d/gcsfuse.list - - path: /etc/apt/sources.list.d/google-chrome.list - path: /etc/apt/sources.list.d/google-cloud-sdk.list - path: /etc/apt/sources.list.d/shutter-next.list - path: /etc/apt/sources.list.d/virtualbox.list @@ -328,7 +328,6 @@ pld_files_remove_bin_path: - name: vault - name: consul - name: helm - - name: ngrok - name: k9s - name: docker-compose - name: ffluf @@ -543,20 +542,20 @@ pld_packages_veeam: - veeam pld_deb: - https://release.gitkraken.com/linux/gitkraken-amd64.deb - - https://github.com/angryip/ipscan/releases/download/3.9.1/ipscan_3.9.1_amd64.deb - - https://github.com/Eugeny/tabby/releases/download/v1.0.215/tabby-1.0.215-linux-x64.deb - - https://github.com/kubernetes/minikube/releases/download/v1.34.0/minikube_1.34.0-0_amd64.deb + - https://github.com/angryip/ipscan/releases/download/3.9.3/ipscan_3.9.3_amd64.deb + - https://github.com/Eugeny/tabby/releases/download/v1.0.228/tabby-1.0.228-linux-x64.deb + - https://github.com/kubernetes/minikube/releases/download/v1.37.0/minikube_1.37.0-0_amd64.deb - https://github.com/wagoodman/dive/releases/download/v0.12.0/dive_0.12.0_linux_amd64.deb - - https://github.com/balena-io/etcher/releases/download/v1.19.25/balena-etcher_1.19.25_amd64.deb + - https://github.com/balena-io/etcher/releases/download/v2.1.4/balena-etcher_2.1.4_amd64.deb - https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.deb - https://github.com/kaikramer/keystore-explorer/releases/download/v5.5.3/kse_5.5.3_all.deb - - https://github.com/aquasecurity/kube-bench/releases/download/v0.9.2/kube-bench_0.9.2_linux_amd64.deb - - https://github.com/anchore/syft/releases/download/v1.15.0/syft_1.15.0_linux_amd64.deb - - https://github.com/turbot/steampipe/releases/download/v1.0.0/steampipe_linux_amd64.deb - - https://github.com/ramboxapp/download/releases/download/v2.4.1/Rambox-2.4.1-linux-x64.deb - - https://github.com/derailed/k9s/releases/download/v0.32.7/k9s_linux_amd64.deb - - https://github.com/getsops/sops/releases/download/v3.9.1/sops_3.9.1_amd64.deb - - https://github.com/atuinsh/atuin/releases/download/v18.2.0/atuin_18.2.0_amd64.deb + - https://github.com/aquasecurity/kube-bench/releases/download/v0.14.1/kube-bench_0.14.1_linux_amd64.deb + - https://github.com/anchore/syft/releases/download/v1.33.0/syft_1.33.0_linux_amd64.deb + - https://github.com/turbot/steampipe/releases/download/v2.2.0/steampipe_linux_amd64.deb + - https://github.com/ramboxapp/download/releases/download/v2.5.2/Rambox-2.5.2-linux-x64.deb + - https://github.com/derailed/k9s/releases/download/v0.50.12/k9s_linux_amd64.deb + - https://github.com/getsops/sops/releases/download/v3.11.0/sops_3.11.0_amd64.deb + - https://github.com/atuinsh/atuin/releases/download/v18.10.0/atuin_18.10.0_amd64.deb - https://cdn.insynchq.com/builds/linux/3.9.4.60020/insync_3.9.4.60020-noble_amd64.deb - https://dl.waveterm.dev/releases-w2/waveterm-linux-amd64-0.9.1.deb pld_flatpak: @@ -638,12 +637,12 @@ pld_unpack: source: amass folder: amass_Linux_amd64 destination_file: amass.zip - - url: https://github.com/yannh/kubeconform/releases/download/v0.6.4/kubeconform-linux-amd64.tar.gz + - url: https://github.com/yannh/kubeconform/releases/download/v0.7.0/kubeconform-linux-amd64.tar.gz destination: kubeconform source: kubeconform folder: destination_file: kubeconform-linux-amd64.tar.gz - - url: https://github.com/terraform-linters/tflint/releases/download/v0.54.0/tflint_linux_amd64.zip + - url: https://github.com/terraform-linters/tflint/releases/download/v0.60.1/tflint_linux_amd64.zip destination: tflint source: tflint destination_file: tflint.zip @@ -658,27 +657,27 @@ pld_unpack: source: krew-linux_amd64 destination_file: krew-linux_amd64.tar.gz folder: - - url: https://github.com/containerd/nerdctl/releases/download/v2.0.0/nerdctl-2.0.0-linux-amd64.tar.gz + - url: https://github.com/containerd/nerdctl/releases/download/v2.1.1/nerdctl-2.1.1-linux-amd64.tar.gz destination: nerdctl source: nerdctl destination_file: nerdctl-linux-amd64.tar.gz folder: - - url: https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.5.0/kustomize_v5.5.0_linux_amd64.tar.gz + - url: https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.8.0/kustomize_v5.8.0_linux_amd64.tar.gz destination: kustomize source: kustomize destination_file: kustomize.tar.gz folder: - - url: https://github.com/doitintl/kube-no-trouble/releases/download/nightly-0.7.3-35-g1afe0af/kubent-nightly-0.7.3-35-g1afe0af-linux-amd64.tar.gz + - url: https://github.com/doitintl/kube-no-trouble/releases/download/0.7.3/kubent-0.7.3-linux-amd64.tar.gz destination: kubent source: kubent destination_file: kubent.tar.gz folder: - - url: https://github.com/nektos/act/releases/download/v0.2.69/act_Linux_x86_64.tar.gz + - url: https://github.com/nektos/act/releases/download/v0.2.88/act_Linux_x86_64.tar.gz destination: act source: act destination_file: act_Linux_x86_64.tar.gz folder: - - url: https://github.com/eza-community/eza/releases/download/v0.20.8/eza_x86_64-unknown-linux-gnu.tar.gz + - url: https://github.com/eza-community/eza/releases/download/v0.23.4/eza_x86_64-unknown-linux-gnu.tar.gz destination: eza source: eza destination_file: eza_x86_64-unknown-linux-gnu.tar.gz @@ -697,13 +696,13 @@ pld_downloads: - url: https://github.com/ffuf/ffuf/releases/download/v2.1.0/ffuf_2.1.0_linux_amd64.tar.gz destination: ffuf skip_tree: false - - url: https://github.com/FairwindsOps/polaris/releases/download/9.6.0/polaris_linux_amd64.tar.gz + - url: https://github.com/FairwindsOps/polaris/releases/download/9.6.3/polaris_linux_amd64.tar.gz destination: polaris skip_tree: false - - url: https://github.com/orf/gping/releases/download/gping-v1.18.0/gping-Linux-x86_64.tar.gz + - url: https://github.com/orf/gping/releases/download/gping-v1.20.1/gping_1.20.1_linux_x86_64.tar.gz destination: gping skip_tree: false - - url: https://github.com/jesseduffield/lazydocker/releases/download/v0.23.3/lazydocker_0.23.3_Linux_x86_64.tar.gz + - url: https://github.com/jesseduffield/lazydocker/releases/download/v0.24.3/lazydocker_0.24.3_Linux_x86_64.tar.gz destination: lazydocker skip_tree: false - url: https://github.com/axiomhq/cli/releases/download/v0.14.0/axiom_0.14.0_linux_amd64.tar.gz @@ -715,21 +714,21 @@ pld_files: - url: https://github.com/dannagle/PacketSender/releases/download/v8.6.5/Packet_Sender_v8.6.5-x86_64.AppImage destination: packetsender desktop_file: ./files/apps/packetsender/packetsender.desktop - - url: https://github.com/k3s-io/k3s/releases/download/v1.31.2%2Bk3s1/k3s + - url: https://github.com/k3s-io/k3s/releases/download/v1.34.2%2Bk3s1/k3s destination: k3s - - url: https://github.com/k3d-io/k3d/releases/download/v5.7.0/k3d-linux-amd64 + - url: https://github.com/k3d-io/k3d/releases/download/v5.8.3/k3d-linux-amd64 destination: k3d - - url: https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 + - url: https://github.com/hadolint/hadolint/releases/download/v2.14.0/hadolint-Linux-x86_64 destination: hadolint - url: https://github.com/alexellis/k3sup/releases/download/0.13.6/k3sup destination: k3sup - - url: https://github.com/argoproj/argo-cd/releases/download/v2.12.7/argocd-linux-amd64 + - url: https://github.com/argoproj/argo-cd/releases/download/v2.14.20/argocd-linux-amd64 destination: argocd - - url: https://github.com/mikefarah/yq/releases/download/v4.44.5/yq_linux_amd64 + - url: https://github.com/mikefarah/yq/releases/download/v4.49.1/yq_linux_amd64 destination: yq - url: https://github.com/patrickvane/shfmt/releases/download/master/shfmt_linux_amd64 destination: shfmt - - url: https://github.com/danielfoehrKn/kubeswitch/releases/download/0.9.2/switcher_linux_amd64 + - url: https://github.com/danielfoehrKn/kubeswitch/releases/download/0.9.3/switcher_linux_amd64 destination: switcher pld_ansible: cfg: /etc/ansible/ansible.cfg diff --git a/scripts/check_versions.py b/scripts/check_versions.py new file mode 100755 index 0000000..6d496c9 --- /dev/null +++ b/scripts/check_versions.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python3 +""" +Check for newer GitHub releases for all tools defined in shared.yml. + +Reads pld_deb, pld_files, pld_downloads, pld_unpack — no extra config. +Non-GitHub URLs (insync CDN, waveterm, gitkraken) are silently skipped. + +Usage: + ./scripts/check_versions.py + ./scripts/check_versions.py --update # rewrite URLs in shared.yml + GITHUB_TOKEN=ghp_... ./scripts/check_versions.py +""" + +import sys +sys.dont_write_bytecode = True + +import json +import os +import re +import subprocess +import urllib.parse +import urllib.request +from pathlib import Path + +try: + import yaml +except ImportError: + sys.exit("pyyaml required: pip install pyyaml") + +SHARED_VARS = Path(__file__).resolve().parent.parent / "roles/pld/vars/shared.yml" +API_URL = "https://api.github.com/repos/{}/releases/latest" +GH_RE = re.compile(r"https://github\.com/([^/\s]+/[^/\s]+)/releases/download/([^/\s]+)/\S+") + + +# --------------------------------------------------------------------------- +# GitHub API +# --------------------------------------------------------------------------- + +def gh_latest(repo, token=None): + req = urllib.request.Request(API_URL.format(repo)) + req.add_header("Accept", "application/vnd.github.v3+json") + req.add_header("User-Agent", "pld-version-checker/1.0") + if token: + req.add_header("Authorization", f"token {token}") + try: + with urllib.request.urlopen(req, timeout=15) as r: + return json.loads(r.read()).get("tag_name") + except urllib.error.HTTPError as e: + if e.code == 404: + return None + print(f" [{repo}] HTTP {e.code}", file=sys.stderr) + return None + except Exception as e: + print(f" [{repo}] {e}", file=sys.stderr) + return None + + +# --------------------------------------------------------------------------- +# Version comparison +# --------------------------------------------------------------------------- + +def to_semver(tag): + """Normalize a tag to a comparable int-tuple, handling all prefix forms.""" + t = urllib.parse.unquote(tag) + t = re.sub(r"^[a-zA-Z][a-zA-Z0-9_.+]*/", "", t) # namespace/ (kustomize/v5) + t = re.sub(r"^[a-zA-Z][a-zA-Z0-9_.+]*-", "", t) # name- (gping-v1) + t = re.sub(r"^v", "", t) + nums = re.findall(r"\d+", t) + return tuple(int(n) for n in nums[:4]) if nums else (0,) + + +# --------------------------------------------------------------------------- +# URL rewriting +# --------------------------------------------------------------------------- + +def rewrite(url, old_encoded, new_tag): + """Replace old_encoded tag with new_tag throughout a GitHub release URL.""" + old_tag = urllib.parse.unquote(old_encoded) + new_encoded = urllib.parse.quote(new_tag, safe="") + + def bare(tag): + t = re.sub(r"^[a-zA-Z][a-zA-Z0-9_.+]*/", "", tag) + t = re.sub(r"^[a-zA-Z][a-zA-Z0-9_.+]*-", "", t) + return re.sub(r"^v", "", t) + + old_bare = bare(old_tag) + new_bare = bare(new_tag) + + marker = f"/releases/download/{old_encoded}/" + if marker in url: + pre, filename = url.split(marker, 1) + return pre + f"/releases/download/{new_encoded}/" + filename.replace(old_bare, new_bare) + + # fallback: blind replace (handles single-file downloads without trailing /) + return url.replace(old_encoded, new_encoded).replace(old_bare, new_bare) + + +# --------------------------------------------------------------------------- +# YAML entry collection +# --------------------------------------------------------------------------- + +def iter_entries(data): + """ + Yield (changelog_tag, name, url, regex_match) for every GitHub release URL + across pld_deb, pld_files, pld_downloads, pld_unpack. + + Driven entirely by the existing YAML payload — no separate mapping needed. + """ + seen = set() + + # pld_deb: plain URL strings + for url in data.get("pld_deb", []): + if not isinstance(url, str) or url in seen: + continue + m = GH_RE.search(url) + if not m: + continue + seen.add(url) + # prefer repo name; fall back to filename stem when repo name is generic + repo_name = m.group(1).split("/")[1] + if repo_name in ("download", "releases", "package"): + stem = Path(urllib.parse.unquote(url.split("/")[-1])).stem + name = re.split(r"[_]", stem)[0].split("-")[0] + else: + name = repo_name + yield "DEB", name, url, m + + # pld_files / pld_downloads / pld_unpack: dicts with a 'url' key + for list_key in ("pld_files", "pld_downloads", "pld_unpack"): + for item in data.get(list_key, []): + url = item.get("url", "") if isinstance(item, dict) else "" + if not url or url in seen: + continue + m = GH_RE.search(url) + if not m: + continue + seen.add(url) + name = item.get("destination") or item.get("name") or "unknown" + yield "PACKAGES", name, url, m + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + do_update = "--update" in sys.argv + token = os.environ.get("GITHUB_TOKEN") + if "--token" in sys.argv: + i = sys.argv.index("--token") + if i + 1 < len(sys.argv): + token = sys.argv[i + 1] + if not token: + try: + token = subprocess.check_output( + ["gh", "auth", "token"], stderr=subprocess.DEVNULL, text=True + ).strip() or None + except Exception: + pass + + raw = SHARED_VARS.read_text() + data = yaml.safe_load(raw) + + repo_cache = {} + results = [] + + for ch_tag, name, url, m in iter_entries(data): + repo, encoded = m.group(1), m.group(2) + current = urllib.parse.unquote(encoded) + + if current in ("master", "latest", "HEAD"): + results.append((ch_tag, name, url, encoded, current, current, "pinned")) + continue + + if repo not in repo_cache: + print(f" {repo} ...", file=sys.stderr) + repo_cache[repo] = gh_latest(repo, token) + latest = repo_cache[repo] + + if latest is None: + results.append((ch_tag, name, url, encoded, current, None, "error")) + elif to_semver(latest) > to_semver(current): + results.append((ch_tag, name, url, encoded, current, latest, "outdated")) + else: + results.append((ch_tag, name, url, encoded, current, latest, "ok")) + + outdated = [r for r in results if r[6] == "outdated"] + ok = [r for r in results if r[6] == "ok"] + skipped = [r for r in results if r[6] in ("pinned", "error")] + + W = 24 + print(f"\n{'─' * 72}") + print(f" PLD version check — {len(results)} tools — {len(outdated)} outdated") + print(f"{'─' * 72}\n") + + if outdated: + print("OUTDATED:") + for ch_tag, name, url, enc, cur, lat, _ in outdated: + print(f" [{name:<{W - 2}}] {cur:<28} → {lat}") + print() + + print(f"UP TO DATE ({len(ok)}):") + for ch_tag, name, url, enc, cur, lat, _ in ok: + print(f" [{name:<{W - 2}}] {cur}") + + if skipped: + print(f"\nSKIPPED ({len(skipped)}):") + for ch_tag, name, url, enc, cur, lat, reason in skipped: + print(f" [{name:<{W - 2}}] {cur:<28} ({reason})") + + if outdated: + print("\nCHANGELOG entries:") + for ch_tag, name, url, enc, cur, lat, _ in outdated: + print(f" - [{ch_tag}] upgraded `{name}` to version {lat}") + + if do_update: + if not outdated: + print("\nNothing to update.") + return + print(f"\nUpdating {SHARED_VARS} ...") + new_raw = raw + for ch_tag, name, url, enc, cur, lat, _ in outdated: + new_url = rewrite(url, enc, lat) + if new_url != url: + new_raw = new_raw.replace(url, new_url) + print(f" {name}: {cur} → {lat}") + else: + print(f" {name}: URL rewrite failed — check manually", file=sys.stderr) + SHARED_VARS.write_text(new_raw) + print("\nReview: git diff roles/pld/vars/shared.yml") + elif outdated: + print("\nRun with --update to apply URL changes to shared.yml.") + + +if __name__ == "__main__": + main()