diff --git a/.azure-pipelines/nightly.yml b/.azure-pipelines/nightly.yml index 05534e216..99f78cc4f 100644 --- a/.azure-pipelines/nightly.yml +++ b/.azure-pipelines/nightly.yml @@ -15,5 +15,5 @@ variables: stages: - template: templates/stages/test-and-package-stage.yml - - template: templates/stages/deploy-stage.yml + - template: templates/stages/nightly-deploy-stage.yml - template: templates/stages/notify-failure-stage.yml diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index edef2d1c3..9ab499ddd 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -13,7 +13,5 @@ variables: stages: - template: templates/stages/test-and-package-stage.yml - template: templates/stages/changelog-stage.yml - - template: templates/stages/deploy-stage.yml - parameters: - snapReleaseChannel: beta + - template: templates/stages/release-deploy-stage.yml - template: templates/stages/notify-failure-stage.yml diff --git a/.azure-pipelines/templates/jobs/snap-deploy-job.yml b/.azure-pipelines/templates/jobs/common-deploy-jobs.yml similarity index 57% rename from .azure-pipelines/templates/jobs/snap-deploy-job.yml rename to .azure-pipelines/templates/jobs/common-deploy-jobs.yml index a3c68af36..705ae1dd3 100644 --- a/.azure-pipelines/templates/jobs/snap-deploy-job.yml +++ b/.azure-pipelines/templates/jobs/common-deploy-jobs.yml @@ -72,3 +72,57 @@ jobs: tools/retry.sh eval snapcraft upload --release=${{ parameters.snapReleaseChannel }} "${SNAP_FILE}" done displayName: Publish to Snap store + # The credentials used in the following jobs are for the shared + # certbotbot account on Docker Hub. The credentials are stored + # in a service account which was created by following the + # instructions at + # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-docreg. + # The name given to this service account must match the value + # given to containerRegistry below. The authentication used when + # creating this service account was a personal access token + # rather than a password to bypass 2FA. When Brad set this up, + # Azure Pipelines failed to verify the credentials with an error + # like "access is forbidden with a JWT issued from a personal + # access token", but after saving them without verification, the + # access token worked when the pipeline actually ran. "Grant + # access to all pipelines" should also be checked on the service + # account. The access token can be deleted on Docker Hub if + # these credentials need to be revoked. + - job: publish_docker_by_arch + pool: + vmImage: ubuntu-22.04 + strategy: + matrix: + arm32v6: + DOCKER_ARCH: arm32v6 + arm64v8: + DOCKER_ARCH: arm64v8 + amd64: + DOCKER_ARCH: amd64 + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: docker_$(DOCKER_ARCH) + path: $(Build.SourcesDirectory) + displayName: Retrieve Docker images + - bash: set -e && docker load --input $(Build.SourcesDirectory)/images.tar + displayName: Load Docker images + - task: Docker@2 + inputs: + command: login + containerRegistry: docker-hub + displayName: Login to Docker Hub + - bash: set -e && tools/docker/deploy_images.sh $(dockerTag) $DOCKER_ARCH + displayName: Deploy the Docker images by architecture + - job: publish_docker_multiarch + dependsOn: publish_docker_by_arch + pool: + vmImage: ubuntu-22.04 + steps: + - task: Docker@2 + inputs: + command: login + containerRegistry: docker-hub + displayName: Login to Docker Hub + - bash: set -e && tools/docker/deploy_manifests.sh $(dockerTag) all + displayName: Deploy the Docker multiarch manifests diff --git a/.azure-pipelines/templates/stages/deploy-stage.yml b/.azure-pipelines/templates/stages/deploy-stage.yml deleted file mode 100644 index 8a8c04e2a..000000000 --- a/.azure-pipelines/templates/stages/deploy-stage.yml +++ /dev/null @@ -1,67 +0,0 @@ -parameters: -# We do not define acceptable values for this parameter here as it is passed -# through to ../jobs/snap-deploy-job.yml which does its own sanity checking. -- name: snapReleaseChannel - type: string - default: edge - -stages: - - stage: Deploy - jobs: - - template: ../jobs/snap-deploy-job.yml - parameters: - snapReleaseChannel: ${{ parameters.snapReleaseChannel }} - # The credentials used in the following jobs are for the shared - # certbotbot account on Docker Hub. The credentials are stored - # in a service account which was created by following the - # instructions at - # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-docreg. - # The name given to this service account must match the value - # given to containerRegistry below. The authentication used when - # creating this service account was a personal access token - # rather than a password to bypass 2FA. When Brad set this up, - # Azure Pipelines failed to verify the credentials with an error - # like "access is forbidden with a JWT issued from a personal - # access token", but after saving them without verification, the - # access token worked when the pipeline actually ran. "Grant - # access to all pipelines" should also be checked on the service - # account. The access token can be deleted on Docker Hub if - # these credentials need to be revoked. - - job: publish_docker_by_arch - pool: - vmImage: ubuntu-22.04 - strategy: - matrix: - arm32v6: - DOCKER_ARCH: arm32v6 - arm64v8: - DOCKER_ARCH: arm64v8 - amd64: - DOCKER_ARCH: amd64 - steps: - - task: DownloadPipelineArtifact@2 - inputs: - artifact: docker_$(DOCKER_ARCH) - path: $(Build.SourcesDirectory) - displayName: Retrieve Docker images - - bash: set -e && docker load --input $(Build.SourcesDirectory)/images.tar - displayName: Load Docker images - - task: Docker@2 - inputs: - command: login - containerRegistry: docker-hub - displayName: Login to Docker Hub - - bash: set -e && tools/docker/deploy_images.sh $(dockerTag) $DOCKER_ARCH - displayName: Deploy the Docker images by architecture - - job: publish_docker_multiarch - dependsOn: publish_docker_by_arch - pool: - vmImage: ubuntu-22.04 - steps: - - task: Docker@2 - inputs: - command: login - containerRegistry: docker-hub - displayName: Login to Docker Hub - - bash: set -e && tools/docker/deploy_manifests.sh $(dockerTag) all - displayName: Deploy the Docker multiarch manifests diff --git a/.azure-pipelines/templates/stages/nightly-deploy-stage.yml b/.azure-pipelines/templates/stages/nightly-deploy-stage.yml new file mode 100644 index 000000000..c8569b28a --- /dev/null +++ b/.azure-pipelines/templates/stages/nightly-deploy-stage.yml @@ -0,0 +1,6 @@ +stages: + - stage: Deploy + jobs: + - template: ../jobs/common-deploy-jobs.yml + parameters: + snapReleaseChannel: edge diff --git a/.azure-pipelines/templates/stages/release-deploy-stage.yml b/.azure-pipelines/templates/stages/release-deploy-stage.yml new file mode 100644 index 000000000..f21c50d52 --- /dev/null +++ b/.azure-pipelines/templates/stages/release-deploy-stage.yml @@ -0,0 +1,21 @@ +stages: + - stage: Deploy + jobs: + - template: ../jobs/common-deploy-jobs.yml + parameters: + snapReleaseChannel: beta + - job: create_github_release + pool: + vmImage: ubuntu-22.04 + steps: + - task: DownloadPipelineArtifact@2 + inputs: + artifact: changelog + path: '$(Pipeline.Workspace)' + - task: GitHubRelease@1 + inputs: + gitHubConnection: github-releases + title: ${{ format('Certbot {0}', replace(variables['Build.SourceBranchName'], 'v', '')) }} + releaseNotesFilePath: '$(Pipeline.Workspace)/release_notes.md' + assets: '$(Build.SourcesDirectory)/packages/{*.tar.gz,SHA256SUMS*}' + addChangeLog: false diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index af026b836..b05ec6c08 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -6,11 +6,16 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Added -* +* The Python source packages which we upload to [PyPI](https://pypi.org/) are + now also being uploaded to + [our releases on GitHub](https://github.com/certbot/certbot/releases) where + we now also include a SHA256SUMS checksum file and a PGP signature for that + file. ### Changed -* +* We no longer publish our beta Windows installer as was originally announced + [here](https://community.letsencrypt.org/t/certbot-discontinuing-windows-beta-support-in-2024/208101). ### Fixed diff --git a/tools/_release.sh b/tools/_release.sh index 766d753b1..bb84f02c8 100755 --- a/tools/_release.sh +++ b/tools/_release.sh @@ -70,7 +70,12 @@ SUBPKGS="certbot $SUBPKGS_NO_CERTBOT" # there tag="v$version" -mv "dist.$version" "dist.$version.$(date +%s).bak" || true +built_package_dir="packages" +if [ -d "$built_package_dir" ]; then + echo "there shouldn't already be a $built_package_dir directory!" + echo "if it's not important, maybe delete it and try running the script again?" + exit 1 +fi git tag --delete "$tag" || true tmpvenv=$(mktemp -d) @@ -139,24 +144,23 @@ do python setup.py sdist python setup.py bdist_wheel - echo "Signing ($pkg_dir)" - for x in dist/*.tar.gz dist/*.whl - do - gpg2 -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign --digest-algo sha256 $x - done - cd - done - -mkdir "dist.$version" +mkdir "$built_package_dir" for pkg_dir in $SUBPKGS do - mv $pkg_dir/dist/* "dist.$version" + mv "$pkg_dir"/dist/* "$built_package_dir" done -echo "Testing packages" -cd "dist.$version" + +cd "$built_package_dir" +echo "Generating checksum file and signing it" +sha256sum *.tar.gz > SHA256SUMS +gpg2 -u "$RELEASE_GPG_KEY" --detach-sign --armor --sign --digest-algo sha256 SHA256SUMS +git add *.tar.gz SHA256SUMS* + +echo "Installing packages to generate documentation" # cd .. is NOT done on purpose: we make sure that all subpackages are # installed from local archives rather than current directory (repo root) VIRTUALENV_NO_DOWNLOAD=1 virtualenv ../venv @@ -198,6 +202,9 @@ while ! git commit --gpg-sign="$RELEASE_GPG_KEY" -m "Release $version"; do done git tag --local-user "$RELEASE_GPG_KEY" --sign --message "Release $version" "$tag" +git rm --cached -r "$built_package_dir" +git commit -m "Remove built packages from git" + # Add master section to CHANGELOG.md header=$(head -n 4 certbot/CHANGELOG.md) body=$(sed s/nextversion/$nextversion/ tools/_changelog_top.txt) diff --git a/tools/finish_release.py b/tools/finish_release.py index 62642d602..958d7672b 100755 --- a/tools/finish_release.py +++ b/tools/finish_release.py @@ -5,7 +5,6 @@ Post-release script to publish artifacts created from Azure Pipelines. This currently includes: * Moving snaps from the beta channel to the stable channel -* Publishing the Windows installer in a GitHub release Setup: - Install the snapcraft command line tool and log in to a privileged account. @@ -14,14 +13,12 @@ Setup: Run: -python tools/finish_release.py --css +python tools/finish_release.py Testing: This script can be safely run between releases. When this is done, the script -should execute successfully until the final step when it tries to set draft -equal to false on the GitHub release. This step should fail because a published -release with that name already exists. +should execute successfully. """ @@ -70,24 +67,9 @@ def parse_args(args): # Use the file's docstring for the help text and don't let argparse reformat it. parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('--css', type=str, required=True, help='hostname of code signing server') return parser.parse_args(args) -def publish_windows(css): - """SSH into CSS and trigger downloading Azure Pipeline assets, sign, and upload to Github - - :param str css: CSS host name - - """ - username = input("CSS username (usually EFF username): ") - host = css - command = "ssh -t {}@{} bash /opt/certbot-misc/css/venv.sh".format(username,host) - - print("SSH into CSS to trigger signing and uploading of Windows installer...") - subprocess.run(command, check=True, universal_newlines=True, shell=True) - - def assert_logged_into_snapcraft(): """Confirms that snapcraft is logged in to an account. @@ -200,16 +182,8 @@ def fetch_version_number(major_version=None): def main(args): parsed_args = parse_args(args) - - css = parsed_args.css version = fetch_version_number() - - # Once the GitHub release has been published, trying to publish it - # again fails. Publishing the snaps can be done multiple times though - # so we do that first to make it easier to run the script again later - # if something goes wrong. promote_snaps(ALL_SNAPS, 'beta', version) - publish_windows(css) if __name__ == "__main__": main(sys.argv[1:])