diff --git a/.azure-pipelines/nightly.yml b/.azure-pipelines/nightly.yml deleted file mode 100644 index 54dada338..000000000 --- a/.azure-pipelines/nightly.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Nightly pipeline running each day for main. -trigger: none -pr: none -schedules: - - cron: "30 4 * * *" - displayName: Nightly build - branches: - include: - - main - always: true - -variables: - dockerTag: nightly - snapBuildTimeout: 19800 - -stages: - - template: templates/stages/test-and-package-stage.yml - - template: templates/stages/changelog-stage.yml - - template: templates/stages/nightly-deploy-stage.yml diff --git a/.github/workflows/changelog_stage.yml b/.github/workflows/changelog_stage.yml new file mode 100644 index 000000000..507f5c074 --- /dev/null +++ b/.github/workflows/changelog_stage.yml @@ -0,0 +1,27 @@ +name: Create changelog +on: + workflow_call: +permissions: + contents: read + +jobs: + prepare: + name: Changelog + runs-on: ubuntu-latest + steps: + # If we change the output filename from `release_notes.md`, it should also be changed in tools/create_github_release.py + - name: checkout + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + - name: Prepare changelog + run: |- + CERTBOT_VERSION="$(cd certbot/src && python -c "import certbot; print(certbot.__version__)" && cd ~-)" + tools/extract_changelog.py "${CERTBOT_VERSION}" >> "${{ runner.temp }}/release_notes.md" + shell: bash + - name: Publish changelog + uses: actions/upload-artifact@v7.0.0 + with: + # If we change the artifact's name, it should also be changed in tools/create_github_release.py + name: changelog + path: "${{ runner.temp }}/release_notes.md" diff --git a/.github/workflows/common_deploy_jobs.yml b/.github/workflows/common_deploy_jobs.yml new file mode 100644 index 000000000..911b4af22 --- /dev/null +++ b/.github/workflows/common_deploy_jobs.yml @@ -0,0 +1,155 @@ +name: Common deploy jobs +on: + workflow_call: + inputs: + dockerTag: + required: true + description: 'tag to assign docker images' + type: string + snapReleaseChannel: + description: 'snap channel to release to' + required: true + type: string + secrets: + SNAPCRAFTCFG: + required: true + DOCKERHUB_TOKEN: + required: true + +permissions: + contents: read + +env: + DOCKER_TAG: "${{ inputs.dockerTag }}" + SNAP_RELEASE_CHANNEL: "${{ inputs.snapReleaseChannel }}" + +jobs: + # This job relies on credentials used to publish the Certbot snaps. This + # credential file was created by running: + # + # snapcraft logout + # snapcraft export-login --channels=beta,edge snapcraft.cfg + # (provide the shared snapcraft credentials when prompted) + # + # Then the contents of the file were added as a secret in Github + # with the name SNAPCRAFTCFG under the Secrets and Variables -> Actions + # section of the settings for the certbot organization. + # + # Revoking these credentials can be done by changing the password of the + # account used to generate the credentials. See + # https://forum.snapcraft.io/t/revoking-exported-credentials/19031 for more + # info. + publish_snap: + name: Publish snap + if: ${{ inputs.snapReleaseChannel == 'edge' || inputs.snapReleaseChannel == 'beta' }} + runs-on: + - 'ubuntu-24.04' + strategy: + fail-fast: false + matrix: + SNAP_ARCH: [amd64, armhf, arm64] + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + - name: Install dependencies + run: |- + sudo apt-get update + sudo apt-get install -y --no-install-recommends snapd + sudo snap install --classic snapcraft + shell: bash + - name: Retrieve Certbot snaps + if: ${{ matrix.SNAP_ARCH == 'armhf' }} + uses: actions/download-artifact@v8.0.1 + with: + name: snaps_${{ matrix.SNAP_ARCH }} + path: "${{ github.workspace }}/snap" + - name: Retrieve Certbot snaps + if: ${{ matrix.SNAP_ARCH != 'armhf' }} + uses: actions/download-artifact@v8.0.1 + with: + pattern: snap-*-${{ matrix.SNAP_ARCH }} + merge-multiple: true + path: "${{ github.workspace }}/snap" + - name: Display structure of downloaded files + run: ls -R "${{ github.workspace }}/snap" + - name: Publish to Snap store + run: |- + export SNAPCRAFT_STORE_CREDENTIALS="${{ secrets.SNAPCRAFTCFG }}" + for SNAP_FILE in snap/*.snap; do + tools/retry.sh eval snapcraft upload --release="${SNAP_RELEASE_CHANNEL}" "${SNAP_FILE}" + done + shell: bash + publish_snap_invalid: + # Fail instead of silently skipping snap release + name: Fail on invalid snapReleaseChannel + if: ${{ inputs.snapReleaseChannel != 'edge' && inputs.snapReleaseChannel != 'beta' }} + runs-on: + - 'ubuntu-latest' + steps: + - name: Fail + run: exit 1 + shell: bash + # The credentials used in the following jobs are for the shared + # certbotbot account on Docker Hub. + # They are located under the certbot organization settings, + # under Secrets and Variables -> Actions. + # DOCKERHUB_USERNAME is saved as a variable. + # DOCKERHUB_TOKEN is a secret, and it is a PAT created by + # following the instructions at + # https://docs.docker.com/security/access-tokens/ + # with Read and Write permissions. The access token can be deleted + # on Docker Hub if these credentials need to be revoked. + # The password is a PAT following the advice given by + # https://github.com/docker/login-action?tab=readme-ov-file#docker-hub + publish_docker_by_arch: + name: Publish docker by arch + runs-on: + - 'ubuntu-24.04' + strategy: + fail-fast: false + matrix: + DOCKER_ARCH: + - arm32v6 + - arm64v8 + - amd64 + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + - name: Retrieve Certbot snaps + uses: actions/download-artifact@v8.0.1 + with: + name: docker_${{ matrix.DOCKER_ARCH }} + path: "${{ github.workspace }}" + - name: Load Docker images + run: docker load --input ${{ github.workspace }}/images.tar + shell: bash + - name: Login to Docker Hub + uses: docker/login-action@v4.1.0 + with: + username: "${{ vars.DOCKERHUB_USERNAME }}" + password: "${{ secrets.DOCKERHUB_TOKEN }}" + - name: Deploy the Docker images by architecture + run: tools/docker/deploy_images.sh "$DOCKER_TAG" ${{ matrix.DOCKER_ARCH }} + shell: bash + publish_docker_multiarch: + name: Publish docker multiarch + needs: publish_docker_by_arch + runs-on: + - 'ubuntu-24.04' + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + with: + persist-credentials: false + - name: Login to Docker Hub + uses: docker/login-action@v4.1.0 + with: + username: "${{ vars.DOCKERHUB_USERNAME }}" + password: "${{ secrets.DOCKERHUB_TOKEN }}" + - name: Deploy the Docker multiarch manifests + run: tools/docker/deploy_manifests.sh "$DOCKER_TAG" all + shell: bash diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 000000000..780ec0076 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,80 @@ +# Nightly pipeline running each day for main. +name: Nightly build +on: + schedule: + - cron: 30 4 * * * + workflow_dispatch: + +jobs: + # The first four jobs could be grouped in a separate workflow, but the github actions UI + # is much nicer if they are instead listed explicitly here. + standard_tests_jobs: + name: Standard tests + permissions: + contents: read + uses: "./.github/workflows/standard_tests_jobs.yml" + extended_tests_jobs: + name: Extended tests + permissions: + contents: read + uses: "./.github/workflows/extended_tests_jobs.yml" + secrets: + AWS_TEST_FARM_PEM: "${{ secrets.AWS_TEST_FARM_PEM }}" + AWS_ACCESS_KEY_ID: "${{ secrets.AWS_ACCESS_KEY_ID }}" + AWS_SECRET_ACCESS_KEY: "${{ secrets.AWS_SECRET_ACCESS_KEY }}" + docker_packaging_jobs: + name: Docker packaging + permissions: + contents: read + uses: "./.github/workflows/docker_packaging_jobs.yml" + with: + dockerTag: nightly + snap_packaging_jobs: + name: Snap packaging + permissions: + contents: read + uses: "./.github/workflows/snap_packaging_jobs.yml" + with: + snapBuildTimeout: 19800 + secrets: + LAUNCHPAD_CREDENTIALS: "${{ secrets.LAUNCHPAD_CREDENTIALS }}" + changelog_stage: + name: Create changelog + permissions: + contents: read + uses: "./.github/workflows/changelog_stage.yml" + nightly_deploy_stage: + name: Nightly deploy + permissions: + contents: read + needs: + - standard_tests_jobs + - extended_tests_jobs + - docker_packaging_jobs + - snap_packaging_jobs + uses: "./.github/workflows/common_deploy_jobs.yml" + secrets: + SNAPCRAFTCFG: "${{ secrets.SNAPCRAFTCFG }}" + DOCKERHUB_TOKEN: "${{ secrets.DOCKERHUB_TOKEN }}" + with: + dockerTag: nightly + snapReleaseChannel: edge + re-run: + needs: + - standard_tests_jobs + - extended_tests_jobs + - docker_packaging_jobs + - snap_packaging_jobs + - changelog_stage + - nightly_deploy_stage + if: failure() && fromJSON(github.run_attempt) < 3 + permissions: + actions: write + checks: write + runs-on: ubuntu-latest + steps: + - env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + GH_DEBUG: api + run: gh workflow run rerun.yml -F run_id=${{ github.run_id }} diff --git a/.github/workflows/rerun.yml b/.github/workflows/rerun.yml new file mode 100644 index 000000000..7a9458733 --- /dev/null +++ b/.github/workflows/rerun.yml @@ -0,0 +1,25 @@ +name: Rerun +on: + workflow_dispatch: + inputs: + run_id: + required: true +permissions: + actions: write + checks: write + +env: + RUN_ID: "${{ inputs.run_id }}" + +jobs: + rerun: + runs-on: ubuntu-latest + steps: + - name: rerun "$RUN_ID" + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + GH_DEBUG: api + run: | + gh run watch "$RUN_ID" > /dev/null 2>&1 + gh run rerun "$RUN_ID" --failed