diff --git a/.github/workflows/chart-lint.yml b/.github/workflows/chart-lint.yml deleted file mode 100644 index ea81c18..0000000 --- a/.github/workflows/chart-lint.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: lint-chart - -on: - pull_request: - paths: - - "charts/**" - -jobs: - lint-test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: "0" - - - name: Run chart-testing (lint) - id: lint - uses: helm/chart-testing-action@v2.0.1 - with: - command: lint - config: .github/ct.yaml - - - name: Create kind cluster - uses: helm/kind-action@v1.1.0 - if: steps.lint.outputs.changed == 'true' - - - name: Run chart-testing (install) - uses: helm/chart-testing-action@v2.0.1 - with: - command: install - config: .github/ct.yaml \ No newline at end of file diff --git a/.github/workflows/check-links.yaml b/.github/workflows/check-links.yaml deleted file mode 100644 index fa50239..0000000 --- a/.github/workflows/check-links.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: "Check links" -on: [pull_request, push] - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Link Checker - id: lc - uses: peter-evans/link-checker@v1 - with: - args: -r *.md *.yaml */*/*.go -x .cluster.local - - name: Fail if there were link errors - run: exit ${{ steps.lc.outputs.exit_code }} - diff --git a/.github/workflows/go-lint.yaml b/.github/workflows/go-lint.yaml deleted file mode 100644 index 061e8f9..0000000 --- a/.github/workflows/go-lint.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: "Go lint" -on: [pull_request, push] - -jobs: - code-lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Lint cmd folder - uses: Jerome1337/golint-action@v1.0.2 - with: - golint-path: './cmd/...' - - name: Lint pkg folder - uses: Jerome1337/golint-action@v1.0.2 - with: - golint-path: './pkg/...' diff --git a/.github/workflows/manifests-tests.yml b/.github/workflows/manifests-tests.yml deleted file mode 100644 index dd808aa..0000000 --- a/.github/workflows/manifests-tests.yml +++ /dev/null @@ -1,55 +0,0 @@ -#This: -#- Periodically ensures our latest releases manifest deploy correctly -#- Ensures that a PR changing any of the manifests (later used for -# producing a release) will not break a deployment of an existing release -# (so we can assume it will not break a new release either) - -name: Manifest deploy - -on: - pull_request: - paths: - - "**/kured-*.yaml" - schedule: - - cron: '0 0 1 * *' - -jobs: - use-manifests: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: "0" - - # We need to unpin kind-action so we can test is new versions of kind - # and therefore kubernetes will break with our manifests - # This creates a 1 node cluster. - - name: Create a default kind cluster - uses: helm/kind-action@master - - # kind-action already installed kind and kubectl. - # Hard code DH_ORG weaveworks so that all forks point to latest image - # from weaveworks. - - name: Deploy with kubectl - run: | - VERSION=$(curl -s https://api.github.com/repos/weaveworks/kured/releases | jq -r .[0].tag_name) - make DH_ORG=weaveworks VERSION=$VERSION manifest - kubectl apply -f kured-{rbac,ds}.yaml - - - name: Show kured is deploying - run: | - sleep 10; kubectl describe ds kured -n kube-system - - - name: Ensure kured is up - uses: nick-invision/retry@v1 - with: - timeout_minutes: 10 - max_attempts: 10 - retry_wait_seconds: 60 - # DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be =1 - command: "kubectl get ds -n kube-system | grep -E 'kured.*1.*1.*1.*1.*1' " - - - name: Show kured is successfully deployed - run: | - kubectl get ds -n kube-system diff --git a/.github/workflows/on-pr-charts.yaml b/.github/workflows/on-pr-charts.yaml new file mode 100644 index 0000000..40adcbe --- /dev/null +++ b/.github/workflows/on-pr-charts.yaml @@ -0,0 +1,41 @@ +#This is just extra testing, for lint check, and basic installation +#If those fail, no need to test the rest of the PR (github will cancel the rest of the builds) +name: PR - charts +on: + pull_request: + paths: + - "charts/**" + +jobs: + lint-chart: + name: Lint helm chart + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: "0" + + - name: Lint charts + uses: helm/chart-testing-action@v2.0.1 + with: + command: lint + config: .github/ct.yaml + + test-chart: + name: Install helm chart + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: "0" + + - name: Create default kind cluster + uses: helm/kind-action@v1.1.0 + + - name: Install chart with chart-testing-action + uses: helm/chart-testing-action@v2.0.1 + with: + command: install + config: .github/ct.yaml diff --git a/.github/workflows/on-pr.yaml b/.github/workflows/on-pr.yaml new file mode 100644 index 0000000..8f14026 --- /dev/null +++ b/.github/workflows/on-pr.yaml @@ -0,0 +1,165 @@ +name: PR +on: + pull_request: + push: + +jobs: + pr-shellcheck: + name: Lint bash code with shellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run ShellCheck + uses: bewuethr/shellcheck-action@v2 + + pr-lint-code: + name: Lint golang code + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Lint cmd folder + uses: Jerome1337/golint-action@v1.0.2 + with: + golint-path: './cmd/...' + - name: Lint pkg folder + uses: Jerome1337/golint-action@v1.0.2 + with: + golint-path: './pkg/...' + + pr-check-docs-links: + name: Check docs for incorrect links + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Link Checker + id: lc + uses: peter-evans/link-checker@v1 + with: + args: -r *.md *.yaml */*/*.go -x .cluster.local + - name: Fail if there were link errors + run: exit ${{ steps.lc.outputs.exit_code }} + + # This should not be made a mandatory test + # It is only used to make us aware of any potential security failure, that + # should trigger a bump of the image in build/. + pr-vuln-scan: + name: Build image and scan it against known vulnerabilities + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" image + - uses: Azure/container-scan@v0 + with: + image-name: docker.io/${{ github.repository_owner }}/kured:${{ github.sha }} + + # If the PRs don't break the behaviour in the helm chart, we can simply publish the helm chart at the time of the release. + e2e-helm: + name: "Functional test of helm chart, e2e testing" + runs-on: ubuntu-latest + # only build with oldest and newest supported, it should be good enough. + strategy: + matrix: + kubernetes: + - 1.17 + - 1.19 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: "0" + - name: Build artifacts + run: | + make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" image + make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" helm-chart + + - name: "Workaround 'Failed to attach 1 to compat systemd cgroup /actions_job/...' on gh actions" + run: | + sudo bash << EOF + cp /etc/docker/daemon.json /etc/docker/daemon.json.old + echo '{}' > /etc/docker/daemon.json + systemctl restart docker || journalctl --no-pager -n 500 + systemctl status docker + EOF + + # Default name for helm/kind-action kind clusters is "chart-testing" + - name: Create 5 node kind cluster + uses: helm/kind-action@master + with: + config: .github/kind-cluster-${{ matrix.kubernetes }}.yaml + + - name: Preload previously built images onto kind cluster + run: kind load docker-image docker.io/${{ github.repository_owner }}/kured:${{ github.sha }} --name chart-testing + + - name: Deploy kured on default namespace with its helm chart + run: | + # Documented in official helm doc to live on the edge + curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + # Refresh bins + hash -r + helm install kured ./charts/kured/ --set configuration.period=1m + kubectl config set-context kind-chart-testing + kubectl get ds --all-namespaces + kubectl describe ds kured + + - name: Ensure kured is ready + uses: nick-invision/retry@v1 + with: + timeout_minutes: 10 + max_attempts: 10 + retry_wait_seconds: 60 + # DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be = 5 + command: "kubectl get ds kured | grep -E 'kured.*5.*5.*5.*5.*5' " + + - name: Create reboot sentinel files + run: | + ./tests/kind/create-reboot-sentinels.sh + + - name: Follow reboot until success + env: + DEBUG: true + run: | + ./tests/kind/follow-coordinated-reboot.sh + + # This workflow is useful when introducing new versions, to ensure our manifests + # still work (even if there might be no manifest 'code' change). + # The version used here is what hasn't been tested with the helm chart + deploy-manifests: + name: Deploy kured with current manifests + runs-on: ubuntu-latest + strategy: + matrix: + kubernetes: + - 1.18 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: "0" + - name: Build artifacts + run: | + make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" image + make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" manifest + - name: Workaround "Failed to attach 1 to compat systemd cgroup /actions_job/..." on gh actions + run: | + sudo bash << EOF + cp /etc/docker/daemon.json /etc/docker/daemon.json.old + echo '{}' > /etc/docker/daemon.json + systemctl restart docker || journalctl --no-pager -n 500 + systemctl status docker + EOF + # Default name for helm/kind-action kind clusters is "chart-testing" + - name: Create kind cluster + uses: helm/kind-action@master + with: + config: .github/kind-cluster-${{ matrix.kubernetes }}.yaml + - name: Preload previously built images onto kind cluster + run: kind load docker-image docker.io/${{ github.repository_owner }}/kured:${{ github.sha }} --name chart-testing + - name: Install kured with kubectl + run: | + kubectl apply -f kured-rbac.yaml && kubectl apply -f kured-ds.yaml + - name: Ensure kured is ready + uses: nick-invision/retry@v1 + with: + timeout_minutes: 10 + max_attempts: 10 + retry_wait_seconds: 60 + # DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be = to cluster_size + command: "kubectl get ds -n kube-system kured | grep -E 'kured.*5.*5.*5.*5.*5'" diff --git a/.github/workflows/chart-release.yml b/.github/workflows/on-release.yaml similarity index 63% rename from .github/workflows/chart-release.yml rename to .github/workflows/on-release.yaml index faef2bf..b7c97a5 100644 --- a/.github/workflows/chart-release.yml +++ b/.github/workflows/on-release.yaml @@ -1,14 +1,17 @@ -name: release-chart +name: Publish release on: - push: - tags: - - "*" + release: + types: published jobs: - publish: + publish-helm-chart: + name: Publish our chart runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + with: + fetch-depth: "0" + - name: Publish Helm chart uses: stefanprodan/helm-gh-pages@master with: diff --git a/.github/workflows/on-tag.yaml b/.github/workflows/on-tag.yaml new file mode 100644 index 0000000..07474c4 --- /dev/null +++ b/.github/workflows/on-tag.yaml @@ -0,0 +1,22 @@ +# when we add a tag to the repo, we should publish the kured image to a public repository +# if it's safe. +# It doesn't mean it's ready for release, but at least it's getting us started. +# The next step is to have a PR with the helm chart, to bump the version of the image used +name: Tag repo +on: + push: + tags: + - "*" + +jobs: + tag-scan-and-push-final-image: + name: "Build, scan, and publish tagged image" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - run: | + make DH_ORG="${{ github.repository_owner }}" VERSION="${GITHUB_REF#refs/tags/}" image + - uses: Azure/container-scan@v0 + with: + image-name: docker.io/${{ github.repository_owner }}/kured:${GITHUB_REF#refs/tags/} + # We should add a step to publish the image on tag. diff --git a/.github/workflows/periodics-daily.yaml b/.github/workflows/periodics-daily.yaml new file mode 100644 index 0000000..bbbcc62 --- /dev/null +++ b/.github/workflows/periodics-daily.yaml @@ -0,0 +1,111 @@ +name: Daily jobs + +on: + schedule: + - cron: "30 1 * * *" + +jobs: + periodics-mark-stale: + name: Mark stale issues and PRs + runs-on: ubuntu-latest + steps: + # Stale by default waits for 60 days before marking PR/issues as stale, and closes them after 7 days. + # Do not expire the first issues that would allow the community to grow. + - uses: actions/stale@v3.0.14 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue was automatically considered stale due to lack of activity. Please update it and/or join our slack channels to promote it, before it automatically closes (in 7 days).' + stale-pr-message: 'This PR was automatically considered stale due to lack of activity. Please refresh it and/or join our slack channels to highlight it, before it automatically closes (in 7 days).' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' + exempt-issue-labels: 'good-first-issue' + + check-docs-links: + name: Check docs for incorrect links + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Link Checker + id: lc + uses: peter-evans/link-checker@v1 + with: + args: -r *.md *.yaml */*/*.go -x .cluster.local + - name: Fail if there were link errors + run: exit ${{ steps.lc.outputs.exit_code }} + + vuln-scan: + name: Build image and scan it against known vulnerabilities + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" image + - uses: Azure/container-scan@v0 + with: + image-name: docker.io/${{ github.repository_owner }}/kured:${{ github.sha }} + + deploy-helm: + name: Ensure a kubernetes change didn't break our code + runs-on: ubuntu-latest + # only build with oldest and newest supported, it should be good enough. + strategy: + matrix: + kubernetes: + - 1.17 + - 1.18 + - 1.19 + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: "0" + - name: Build artifacts + run: | + make DH_ORG="${{ github.repository_owner }}" VERSION="master" image + make DH_ORG="${{ github.repository_owner }}" VERSION="master" helm-chart + + - name: "Workaround 'Failed to attach 1 to compat systemd cgroup /actions_job/...' on gh actions" + run: | + sudo bash << EOF + cp /etc/docker/daemon.json /etc/docker/daemon.json.old + echo '{}' > /etc/docker/daemon.json + systemctl restart docker || journalctl --no-pager -n 500 + systemctl status docker + EOF + + # Default name for helm/kind-action kind clusters is "chart-testing" + - name: Create 5 node kind cluster + uses: helm/kind-action@master + with: + config: .github/kind-cluster-${{ matrix.kubernetes }}.yaml + + - name: Preload previously built images onto kind cluster + run: kind load docker-image docker.io/${{ github.repository_owner }}/kured:master --name chart-testing + + - name: Deploy kured on default namespace with its helm chart + run: | + # Documented in official helm doc to live on the edge + curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + # Refresh bins + hash -r + helm install kured ./charts/kured/ --set configuration.period=1m + kubectl config set-context kind-chart-testing + kubectl get ds --all-namespaces + kubectl describe ds kured + + - name: Ensure kured is ready + uses: nick-invision/retry@v1 + with: + timeout_minutes: 10 + max_attempts: 10 + retry_wait_seconds: 60 + # DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be = 5 + command: "kubectl get ds kured | grep -E 'kured.*5.*5.*5.*5.*5' " + + - name: Create reboot sentinel files + run: | + ./tests/kind/create-reboot-sentinels.sh + + - name: Follow reboot until success + env: + DEBUG: true + run: | + ./tests/kind/follow-coordinated-reboot.sh diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml deleted file mode 100644 index aabfe2c..0000000 --- a/.github/workflows/shellcheck.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: "Shellcheck" -on: [pull_request] - -jobs: - bash-lint: - name: Shellcheck - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run ShellCheck - uses: bewuethr/shellcheck-action@v2 diff --git a/.github/workflows/smoke-tests.yml b/.github/workflows/smoke-tests.yml deleted file mode 100644 index 03b1e56..0000000 --- a/.github/workflows/smoke-tests.yml +++ /dev/null @@ -1,74 +0,0 @@ -# This needs all the previous artifacts to be created: -# the image should be published, the repo should be tagged, the helm -# chart pushed. It's assumed everything is working, and we are doing -# a last final test at the release creation time to _ensure_ we can -# release. At this point it's still time to back off in case of problem, -# not publish the release and iterate on tags. - -name: Smoke test - -on: - push: - branches: - - '**' - release: - types: created - -jobs: - deploy-manifests: - runs-on: ubuntu-latest - strategy: - matrix: - kubernetes-version: - - 1.17 - - 1.18 - - 1.19 - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: "0" - - - name: Workaround "Failed to attach 1 to compat systemd cgroup /actions_job/..." on gh actions - run: | - sudo bash << EOF - cp /etc/docker/daemon.json /etc/docker/daemon.json.old - echo '{}' > /etc/docker/daemon.json - systemctl restart docker || journalctl --no-pager -n 500 - systemctl status docker - EOF - - - name: Create 5 node kind cluster - uses: helm/kind-action@master - with: - config: .github/kind-cluster-${{ matrix.kubernetes-version}}.yaml - - - name: Deploy kured on default namespace with its helm chart - run: | - # Documented in official helm doc to live on the edge - curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash - # Refresh bins - hash -r - helm install kured ./charts/kured/ --set configuration.period=1m - kubectl config set-context kind-chart-testing - kubectl get ds --all-namespaces - kubectl describe ds kured - - - name: Ensure kured is ready - uses: nick-invision/retry@v2.2.0 - with: - timeout_minutes: 10 - max_attempts: 10 - retry_wait_seconds: 60 - # DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be = 5 - command: "kubectl get ds kured | grep -E 'kured.*5.*5.*5.*5.*5' " - - - name: Create reboot sentinel files - run: | - ./tests/kind/create-reboot-sentinels.sh - - - name: Follow reboot until success - env: - DEBUG: true - run: | - ./tests/kind/follow-coordinated-reboot.sh diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml deleted file mode 100644 index 0586435..0000000 --- a/.github/workflows/stale.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: Mark stale issues and pull requests - -on: - schedule: - - cron: "30 1 * * *" - -jobs: - stale: - runs-on: ubuntu-latest - steps: - # Stale by default waits for 60 days before marking PR/issues as stale, and closes them after 7 days. - # Do not expire the first issues that would allow the community to grow. - - uses: actions/stale@v3.0.14 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-issue-message: 'This issue was automatically considered stale due to lack of activity. Please update it and/or join our slack channels to promote it, before it automatically closes (in 7 days).' - stale-pr-message: 'This PR was automatically considered stale due to lack of activity. Please refresh it and/or join our slack channels to highlight it, before it automatically closes (in 7 days).' - stale-issue-label: 'no-issue-activity' - stale-pr-label: 'no-pr-activity' - exempt-issue-labels: 'good-first-issue' diff --git a/.github/workflows/vulnerability-scan.yaml b/.github/workflows/vulnerability-scan.yaml deleted file mode 100644 index b5bb93b..0000000 --- a/.github/workflows/vulnerability-scan.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# This should not be made a mandatory test -# It is only used to make us aware of any potential security failure, that -# should trigger a bump of the image in build/. -name: "Image vulnerability scan" -on: [push, pull_request] -jobs: - build-and-scan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - run: make DH_ORG="${{ github.repository_owner }}" VERSION="${{ github.sha }}" image - - uses: Azure/container-scan@v0 - with: - image-name: docker.io/${{ github.repository_owner }}/kured:${{ github.sha }} diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 8a0e975..92b6095 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -31,8 +31,8 @@ the main [README][readme] as well. Before `kured` is released, we want to make sure it still works fine on the previous, current and next minor version of Kubernetes (with respect to the -embedded `client-go` & `kubectl`). For local testing e.g. `minikube` can be -sufficient. +embedded `client-go` & `kubectl`). For local testing e.g. `minikube` or +`kind` can be sufficient. Deploy kured in your test scenario, make sure you pass the right `image`, update the e.g. `period` and `reboot-days` options, so you get immediate @@ -82,36 +82,74 @@ If all the tests ran well, kured maintainers can reach out to the Weaveworks team to get an upcoming `kured` release tested in the Dev environment for real life testing. +### Testing with `kind` + +A test-run with `kind` could look like this: + +```console +# create kind cluster +kind create cluster --config .github/kind-cluster.yaml + +# create reboot required files on pre-defined kind nodes +./tests/create-reboot-sentinels.sh + +# check if reboot is working fine +./tests/kind/follow-coordinated-reboot.sh + +``` + ## Publishing a new kured release +### Prepare Documentation Check that `README.md` has an updated compatibility matrix and that the url in the `kubectl` incantation (under "Installation") is updated to the new version you want to release. +### Create a tag on the repo and publish the image + +Before going further, we should freeze the code for a release, by +tagging the code, and publishing its immutable artifact: the kured +docker image. + +```sh +make DH_ORG="weaveworks" VERSION="1.3.0" image +``` + +Then docker push the image. In the future, that might be automatically +done when creating a tag on the repository, with the help of github +actions. + +### Prepare Helm chart + +You should also check that the helm chart has been updated before issuing +a release. You can bump the helm chart with the latest image +tag by running: + +```sh +make DH_ORG="weaveworks" VERSION="1.3.0" helm-chart +``` + +Finally bump the `version` in `charts/kured/Chart.yaml` (following +the versioning rules) and you should be all set. + +### Create the combined manifest + + Now create the `kured--dockerhub.yaml` for e.g. `1.3.0`: ```sh VERSION=1.3.0 MANIFEST="kured-$VERSION-dockerhub.yaml" +make DH_ORG="weaveworks" VERSION="${VERSION}" manifest cat kured-rbac.yaml > "$MANIFEST" cat kured-ds.yaml >> "$MANIFEST" -sed -i "s#docker.io/weaveworks/kured#docker.io/weaveworks/kured:$VERSION#g" "$MANIFEST" ``` - -To make this available for our Helm users, please make sure you update the -image version in - -- `charts/kured/values.yaml` (`tag`), -- `charts/kured/Chart.yaml` (`appVersion`) and -- `charts/kured/README.md` (`image.tag`) as well. - -Finally bump the `version` in `charts/kured/Chart.yaml` and you should be -all set. +### Publish release artifacts Now you can head to the Github UI, use the version number as tag and upload the `kured--dockerhub.yaml` file. -### Release notes +The creation of the release will publish the helm chart (thanks to github actions). Please describe what's new and noteworthy in the release notes, list the PRs that landed and give a shout-out to everyone who contributed.