From 359a8e80f782f9761826c7cfd624bc05ddb4d7d2 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 11 Apr 2023 14:36:57 +0100 Subject: [PATCH 01/11] Add actionlint to pre-commit Signed-off-by: Pedro Algarvio --- .github/actionlint.yaml | 4 ++++ .pre-commit-config.yaml | 13 +++++++++++ tools/__init__.py | 8 +++++++ tools/pre_commit.py | 51 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 .github/actionlint.yaml create mode 100644 tools/__init__.py create mode 100644 tools/pre_commit.py diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 000000000..093a4fd41 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,4 @@ +self-hosted-runner: + # Labels of self-hosted runner in array of string + labels: + - repo-release diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b4d63be12..e382ccacc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,6 +21,19 @@ repos: hooks: - id: black + - repo: https://github.com/s0undt3ch/python-tools-scripts + rev: "0.12.0" + hooks: + - id: tools + alias: actionlint + name: Lint GitHub Actions Workflows + files: "^.github/workflows/" + types: + - yaml + args: + - pre-commit + - actionlint + - repo: local hooks: - id: generate-actions-workflow diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 000000000..f1a241887 --- /dev/null +++ b/tools/__init__.py @@ -0,0 +1,8 @@ +import logging + +import ptscripts + +ptscripts.register_tools_module("tools.pre_commit") + +for name in ("boto3", "botocore", "urllib3"): + logging.getLogger(name).setLevel(logging.INFO) diff --git a/tools/pre_commit.py b/tools/pre_commit.py new file mode 100644 index 000000000..da24bf820 --- /dev/null +++ b/tools/pre_commit.py @@ -0,0 +1,51 @@ +""" +These commands are used by pre-commit. +""" +# pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated +from __future__ import annotations + +import logging +import shutil + +from ptscripts import Context, command_group + + +log = logging.getLogger(__name__) + +# Define the command group +cgroup = command_group( + name="pre-commit", help="Pre-Commit Related Commands", description=__doc__ +) + + +@cgroup.command( + name="actionlint", + arguments={ + "files": { + "help": "Files to run actionlint against", + "nargs": "*", + }, + "no_color": { + "help": "Disable colors in output", + }, + }, +) +def actionlint(ctx: Context, files: list[str], no_color: bool = False): + """ + Run `actionlint` + """ + actionlint = shutil.which("actionlint") + if not actionlint: + ctx.warn("Could not find the 'actionlint' binary") + ctx.exit(0) + cmdline = [actionlint] + if no_color is False: + cmdline.append("-color") + shellcheck = shutil.which("shellcheck") + if shellcheck: + cmdline.append(f"-shellcheck={shellcheck}") + pyflakes = shutil.which("pyflakes") + if pyflakes: + cmdline.append(f"-pyflakes={pyflakes}") + ret = ctx.run(*cmdline, *files, check=False) + ctx.exit(ret.returncode) From b51840eda41ff9aabe341209c0175be337dbefc8 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 11 Apr 2023 15:00:55 +0100 Subject: [PATCH 02/11] Use our runners to publish a release. Update S3 bucket in the process. Signed-off-by: Pedro Algarvio --- .github/workflows/release.yml | 356 +++++++++++++++++------ .github/workflows/scripts/cut-release.py | 8 + 2 files changed, 281 insertions(+), 83 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2f6550c55..ea062426a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,13 +3,11 @@ name: Cut Release on: workflow_dispatch jobs: - update-develop: - name: Update CHANGELOG.md and bootstrap-salt.sh + + check-requirements: + name: Check Requirements runs-on: ubuntu-latest - if: github.repository == 'saltstack/salt-bootstrap' - permissions: - contents: write # To be able to publish the release - environment: Release + environment: release-check steps: - name: Check For Admin Permission uses: actions-cool/check-user-permission@v2 @@ -17,42 +15,104 @@ jobs: require: admin username: ${{ github.triggering_actor }} - - name: Check Branch Triggering Release + - name: Check Repository run: | - if [ "${{ github.ref_name }}" != "develop" ] - then - echo "This workflow should only be triggered from the develop branch" - exit 1 + echo "Trying to run the release workflow from repository ${{ github.repository }}" + if [ "${{ github.repository }}" != "saltstack/salt-bootstrap" ]; then + echo "Running the release workflow from the ${{ github.repository }} repository is not allowed" + echo "Allowed repository: saltstack/salt-bootstrap" + exit 1 + else + echo "Allowed to release from repository ${{ github.repository }}" + fi + + - name: Check Branch + run: | + echo "Trying to run the release workflow from branch ${{ github.ref_name }}" + if [ "${{ github.ref_name }}" != "develop" ]; then + echo "Running the release workflow from the ${{ github.ref_name }} branch is not allowed" + echo "Allowed branches: develop" + exit 1 + else + echo "Allowed to release from branch ${{ github.ref_name }}" fi + update-develop: + name: Update CHANGELOG.md and bootstrap-salt.sh + runs-on: + - self-hosted + - linux + - repo-release + permissions: + contents: write # To be able to publish the release + environment: release + needs: + - check-requirements + outputs: + release-changes: ${{ steps.update-repo.outputs.release-changes }} + release-version: ${{ steps.update-repo.outputs.release-version }} + steps: - uses: actions/checkout@v3 with: ref: develop repository: ${{ github.repository }} ssh-key: ${{ secrets.SALT_BOOTSTRAP_RELEASE_KEY }} - - name: Update Git Settings - run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot] on behalf of ${{ github.event.sender.login }}" - - - name: Set up Python 3.7 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: "3.10" - name: Install Requirements run: | python3 -m pip install requests pre-commit pre-commit install --install-hooks + - name: Setup GnuPG + run: | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} + run: | + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + + - name: Configure Git + shell: bash + run: | + git config --global --add safe.directory "$(pwd)" + git config --global user.name "Salt Project Packaging" + git config --global user.email saltproject-packaging@vmware.com + git config --global user.signingkey 64CBBC8173D76B3F + git config --global commit.gpgsign true + - name: Update Repository + id: update-repo env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python3 .github/workflows/scripts/cut-release.py --repo ${{ github.repository }} - export CUT_RELEASE_VERSION=$(cat .cut_release_version) - echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV - name: Show Changes run: | @@ -61,15 +121,16 @@ jobs: - name: Commit Changes run: | - git commit -am "Update develop branch for the ${CUT_RELEASE_VERSION} release" || \ - git commit -am "Update develop branch for the ${CUT_RELEASE_VERSION} release" + git commit -am "Update develop branch for the ${{ steps.update-repo.outputs.release-version }} release" || \ + git commit -am "Update develop branch for the ${{ steps.update-repo.outputs.release-version }} release" - name: Push Changes - uses: ad-m/github-push-action@master + uses: ad-m/github-push-action@b87afee92c6e70ea888be6203a3e9426fda49839 with: - repository: ${{ github.repository }} - branch: develop ssh: true + atomic: true + branch: develop + repository: ${{ github.repository }} - name: Upload Release Details uses: actions/upload-artifact@v3 @@ -81,10 +142,13 @@ jobs: merge-develop-into-stable: name: Merge develop into stable - runs-on: ubuntu-latest - if: github.repository == 'saltstack/salt-bootstrap' - needs: update-develop - environment: Release + runs-on: + - self-hosted + - linux + - repo-release + needs: + - update-develop + environment: release permissions: contents: write # To be able to publish the release steps: @@ -95,64 +159,90 @@ jobs: ssh-key: ${{ secrets.SALT_BOOTSTRAP_RELEASE_KEY }} fetch-depth: 0 - - name: Update Git Settings + - name: Setup GnuPG + run: | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot] on behalf of @${{ github.event.sender.login }}" + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + + - name: Configure Git + shell: bash + run: | + git config --global --add safe.directory "$(pwd)" + git config --global user.name "Salt Project Packaging" + git config --global user.email saltproject-packaging@vmware.com + git config --global user.signingkey 64CBBC8173D76B3F + git config --global commit.gpgsign true - name: Download Release Details uses: actions/download-artifact@v3 with: name: release-details - - name: Update Environment - run: | - export CUT_RELEASE_VERSION=$(cat .cut_release_version) - echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV - - name: Merge develop into stable run: | - git merge --no-ff -m "Merge develop into stable for ${CUT_RELEASE_VERSION} release" origin/develop || touch .git-conflicts + git merge --no-ff -m "Merge develop into stable for ${{ needs.update-develop.outputs.release-version }} release" origin/develop || touch .git-conflicts if [ -f .git-conflicts ] then git diff for f in $(git status | grep 'both modified' | awk '{ print $3 }') do - git checkout --theirs $f - pre-commit run -av --files $f - git add $f + git checkout --theirs "$f" + pre-commit run -av --files "$f" + git add "$f" done - git commit -a -m "Merge develop into stable for ${CUT_RELEASE_VERSION} release(auto resolving conflicts to the develop version)" + git commit -a -m "Merge develop into stable for ${{ needs.update-develop.outputs.release-version }} release(auto resolving conflicts to the develop version)" fi - - name: Tag Release - uses: mathieudutour/github-tag-action@v6.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - custom_tag: ${{ env.CUT_RELEASE_VERSION }} - tag_prefix: "" - create_annotated_tag: true + - name: Tag The ${{ needs.update-develop.outputs.release-version }} Release + run: | + git tag -m "Release ${{ needs.update-develop.outputs.release-version }}" -as ${{ needs.update-develop.outputs.release-version }} - name: Update bootstrap-salt.sh sha256sum's run: | - echo "$(sha256sum bootstrap-salt.sh | awk '{ print $1 }')" > bootstrap-salt.sh.sha256 - echo "$(sha256sum bootstrap-salt.ps1 | awk '{ print $1 }')" > bootstrap-salt.ps1.sha256 + sha256sum bootstrap-salt.sh | awk '{ print $1 }' > bootstrap-salt.sh.sha256 + sha256sum bootstrap-salt.ps1 | awk '{ print $1 }' > bootstrap-salt.ps1.sha256 git commit -a -m "Update sha256 checksums" || git commit -a -m "Update sha256 checksums" - name: Push Changes - uses: ad-m/github-push-action@master + uses: ad-m/github-push-action@b87afee92c6e70ea888be6203a3e9426fda49839 with: - repository: ${{ github.repository }} - branch: stable - tags: true ssh: true + tags: true + atomic: true + branch: stable + repository: ${{ github.repository }} publish-release: name: Create GitHub Release runs-on: ubuntu-latest - if: github.repository == 'saltstack/salt-bootstrap' - needs: merge-develop-into-stable - environment: Release + needs: + - merge-develop-into-stable + environment: release permissions: contents: write # To be able to publish the release steps: @@ -168,8 +258,8 @@ jobs: - name: Update Environment run: | - export CUT_RELEASE_VERSION=$(cat .cut_release_version) - echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> $GITHUB_ENV + CUT_RELEASE_VERSION=$(cat .cut_release_version) + echo "CUT_RELEASE_VERSION=${CUT_RELEASE_VERSION}" >> "$GITHUB_ENV" - name: Create Github Release uses: softprops/action-gh-release@v1 @@ -194,12 +284,38 @@ jobs: name: release-details failOnError: false + update-s3-bucket: + name: Update S3 Bucket + runs-on: + - self-hosted + - linux + - repo-release + needs: + - publish-release + environment: release + + steps: + - uses: actions/checkout@v3 + with: + ref: stable + repository: ${{ github.repository }} + + - name: Upload Stable Release to S3 + run: | + files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256" + for fname in $files; do + aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/stable/${fname}" + done + update-develop-checksums: name: Update Release Checksums on Develop - runs-on: ubuntu-latest - if: github.repository == 'saltstack/salt-bootstrap' - needs: publish-release - environment: Release + runs-on: + - self-hosted + - linux + - repo-release + needs: + - publish-release + environment: release permissions: contents: write # For action peter-evans/create-pull-request pull-requests: write # For action peter-evans/create-pull-request @@ -213,8 +329,8 @@ jobs: - name: Get bootstrap-salt.sh on stable branch sha256sum run: | - echo "SH=$(sha256sum bootstrap-salt.sh | awk '{ print $1 }')" >> $GITHUB_ENV - echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> $GITHUB_ENV + echo "SH=$(sha256sum bootstrap-salt.sh | awk '{ print $1 }')" >> "$GITHUB_ENV" + echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> "$GITHUB_ENV" - uses: actions/checkout@v3 with: @@ -222,15 +338,49 @@ jobs: repository: ${{ github.repository }} ssh-key: ${{ secrets.SALT_BOOTSTRAP_RELEASE_KEY }} - - name: Update Git Settings + - name: Setup GnuPG run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot] on behalf of @${{ github.event.sender.login }}" + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} + run: | + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + + - name: Configure Git + shell: bash + run: | + git config --global --add safe.directory "$(pwd)" + git config --global user.name "Salt Project Packaging" + git config --global user.email saltproject-packaging@vmware.com + git config --global user.signingkey 64CBBC8173D76B3F + git config --global commit.gpgsign true - - name: Set up Python 3.7 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: "3.10" - name: Update Latest Release on README run: | @@ -247,19 +397,23 @@ jobs: git commit -am "Update README.rst with ${{ env.BS_VERSION }} release sha256sum" - name: Push Changes - uses: ad-m/github-push-action@master + uses: ad-m/github-push-action@b87afee92c6e70ea888be6203a3e9426fda49839 with: - repository: ${{ github.repository }} - branch: develop ssh: true + atomic: true + branch: develop + repository: ${{ github.repository }} salt: name: Update Release on Salt Repo - runs-on: ubuntu-latest - if: github.repository == 'saltstack/salt-bootstrap' - needs: update-develop-checksums - environment: Open PR Against Salt + runs-on: + - self-hosted + - linux + - repo-release + needs: + - update-develop-checksums + environment: release permissions: contents: write # For action peter-evans/create-pull-request pull-requests: write # For action peter-evans/create-pull-request @@ -272,7 +426,7 @@ jobs: - name: Get bootstrap version run: | - echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> $GITHUB_ENV + echo "BS_VERSION=$(sh bootstrap-salt.sh -v | awk '{ print $4 }')" >> "$GITHUB_ENV" - uses: actions/checkout@v3 with: @@ -281,17 +435,51 @@ jobs: path: salt-checkout token: ${{ secrets.SALT_REPO_WRITE_TOKEN }} - - name: Update Git Settings + - name: Setup GnuPG + run: | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} + run: | + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + + - name: Configure Git + shell: bash run: | - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot] on behalf of @${{ github.event.sender.login }}" + git config --global --add safe.directory "$(pwd)" + git config --global user.name "Salt Project Packaging" + git config --global user.email saltproject-packaging@vmware.com + git config --global user.signingkey 64CBBC8173D76B3F + git config --global commit.gpgsign true - name: Update bootstrap script on Salt run: | cp bootstrap-salt.sh salt-checkout/salt/cloud/deploy/bootstrap-salt.sh - name: Create Pull Request Against Develop - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v5 with: title: "Update the bootstrap script to v${{ env.BS_VERSION }}" path: salt-checkout @@ -299,3 +487,5 @@ jobs: token: ${{ secrets.SALT_REPO_WRITE_TOKEN }} commit-message: Update the bootstrap script to v${{ env.BS_VERSION }} delete-branch: true + add-paths: | + salt-checkout/salt/cloud/deploy/bootstrap-salt.sh diff --git a/.github/workflows/scripts/cut-release.py b/.github/workflows/scripts/cut-release.py index 4cbda55f9..569907ccb 100644 --- a/.github/workflows/scripts/cut-release.py +++ b/.github/workflows/scripts/cut-release.py @@ -155,6 +155,8 @@ def main(): message=f"Unable to generate changelog. HTTP Response:\n{changelog}", ) + github_output = os.environ.get("GITHUB_OUTPUT") + cut_release_version = REPO_ROOT / ".cut_release_version" print( f"* Writing {cut_release_version.relative_to(REPO_ROOT)} ...", @@ -162,6 +164,9 @@ def main(): flush=True, ) cut_release_version.write_text(options.release_tag) + if github_output is not None: + with open(github_output, "a", encoding="utf-8") as wfh: + wfh.write(f"release-version={options.release_tag}\n") cut_release_changes = REPO_ROOT / ".cut_release_changes" print( @@ -170,6 +175,9 @@ def main(): flush=True, ) cut_release_changes.write_text(changelog["body"]) + if github_output is not None: + with open(github_output, "a", encoding="utf-8") as wfh: + wfh.write(f"release-changes={changelog['body']}\n") print( f"* Updating {changelog_file.relative_to(REPO_ROOT)} ...", From c981eae0cb83f12fa97242c60dd444a02624b9b2 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 11 Apr 2023 15:20:21 +0100 Subject: [PATCH 03/11] Sign release scripts. Nightly develop version of scripts upload. Signed-off-by: Pedro Algarvio --- .github/workflows/nightly.yml | 98 +++++++++++++++++++++++++++++++++++ .github/workflows/release.yml | 36 ++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/nightly.yml diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 000000000..95b5c86de --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,98 @@ +name: Nightly S3 Update +run-name: "Nightly S3 (branch: ${{ github.ref_name }})" + +on: + workflow_dispatch: {} + schedule: + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onschedule + - cron: '0 1 * * *' # Every day at 1AM + +jobs: + + workflow-requirements: + name: Check Workflow Requirements + runs-on: ubuntu-latest + outputs: + requirements-met: ${{ steps.check-requirements.outputs.requirements-met }} + steps: + - name: Check For Admin Permission + if: ${{ github.event_name != 'schedule' }} + uses: actions-cool/check-user-permission@v2 + with: + require: admin + username: ${{ github.triggering_actor }} + + - name: Check Requirements + id: check-requirements + run: | + if [ "${{ vars.RUN_SCHEDULED_BUILDS }}" = "1" ]; then + MSG="Running workflow because RUN_SCHEDULED_BUILDS=1" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=true" >> "${GITHUB_OUTPUT}" + elif [ "${{ github.event.repository.fork }}" = "true" ]; then + MSG="Not running workflow because ${{ github.repository }} is a fork" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=false" >> "${GITHUB_OUTPUT}" + else + MSG="Running workflow because ${{ github.repository }} is not a fork" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=true" >> "${GITHUB_OUTPUT}" + fi + + update-s3-bucket: + name: Update S3 Bucket + if: ${{ fromJSON(needs.workflow-requirements.outputs.requirements-met) }} + runs-on: + - self-hosted + - linux + - repo-release + needs: + - workflow-requirements + environment: release + + steps: + - uses: actions/checkout@v3 + + - name: Setup GnuPG + run: | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} + run: | + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + + - name: Upload Develop to S3 + run: | + gpg --output SALT-PROJECT-GPG-PUBKEY-2023.gpg --export 64CBBC8173D76B3F + gpg --armor --output SALT-PROJECT-GPG-PUBKEY-2023.pub --export 64CBBC8173D76B3F + files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub" + for fname in $files; do + gpg --local-user 64CBBC8173D76B3F --output "${fname}.asc" --armor --detach-sign --sign "${fpath}" + aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}" + aws s3 cp "${fname}.asc" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}.asc" + done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea062426a..a9c96e20d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -300,11 +300,45 @@ jobs: ref: stable repository: ${{ github.repository }} + - name: Setup GnuPG + run: | + sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg + GNUPGHOME="$(mktemp -d -p /run/gpg)" + echo "GNUPGHOME=${GNUPGHOME}" >> "$GITHUB_ENV" + cat < "${GNUPGHOME}/gpg.conf" + batch + no-tty + pinentry-mode loopback + EOF + + - name: Get Secrets + id: get-secrets + env: + SECRETS_KEY: ${{ secrets.SECRETS_KEY }} + run: | + SECRETS_KEY_FILE=$(mktemp /tmp/output.XXXXXXXXXX) + echo "$SECRETS_KEY" > "$SECRETS_KEY_FILE" + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text | jq .default_key -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -d - \ + | gpg --import - + sync + aws --region us-west-2 secretsmanager get-secret-value --secret-id /cmbu-saltstack/signing/repo-signing-keys-sha256-2023 \ + --query SecretString --output text| jq .default_passphrase -r | base64 -d \ + | gpg --passphrase-file "${SECRETS_KEY_FILE}" -o "${GNUPGHOME}/passphrase" -d - + sync + rm "$SECRETS_KEY_FILE" + echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + - name: Upload Stable Release to S3 run: | - files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256" + gpg --output SALT-PROJECT-GPG-PUBKEY-2023.gpg --export 64CBBC8173D76B3F + gpg --armor --output SALT-PROJECT-GPG-PUBKEY-2023.pub --export 64CBBC8173D76B3F + files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub" for fname in $files; do + gpg --local-user 64CBBC8173D76B3F --output "${fname}.asc" --armor --detach-sign --sign "${fpath}" aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/stable/${fname}" + aws s3 cp "${fname}.asc" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/stable/${fname}.asc" done update-develop-checksums: From af258021fa9f48e1ade025e2c817078e2e87b30e Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 11 Apr 2023 15:55:22 +0100 Subject: [PATCH 04/11] Some echo's so that we know what we're doing Signed-off-by: Pedro Algarvio --- .github/workflows/nightly.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 95b5c86de..72ca6cf28 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -88,11 +88,16 @@ jobs: - name: Upload Develop to S3 run: | + echo "Exporting GPG Key" gpg --output SALT-PROJECT-GPG-PUBKEY-2023.gpg --export 64CBBC8173D76B3F + echo "Exporting Armored GPG Key" gpg --armor --output SALT-PROJECT-GPG-PUBKEY-2023.pub --export 64CBBC8173D76B3F - files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub" - for fname in $files; do + declare -a files=("bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub") + for fname in "${files[@]}" + do + echo "GPG Signing ${fpath} ..." gpg --local-user 64CBBC8173D76B3F --output "${fname}.asc" --armor --detach-sign --sign "${fpath}" + echo "Uploading ${fpath} and ${fpath}.asc to S3" aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}" aws s3 cp "${fname}.asc" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}.asc" done From 453812a6ea2d6c1dc2f4ca6ca235c1081402a9b0 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 11 Apr 2023 17:16:05 +0100 Subject: [PATCH 05/11] Switch to using `tools` when uploading to S3 Signed-off-by: Pedro Algarvio --- .github/workflows/nightly.yml | 29 +++++---- .github/workflows/release.yml | 29 +++++---- .pre-commit-config.yaml | 57 +++++++++++++++-- requirements/release.in | 3 + requirements/release.txt | 69 +++++++++++++++++++++ tools/__init__.py | 1 + tools/release.py | 113 ++++++++++++++++++++++++++++++++++ tools/utils.py | 80 ++++++++++++++++++++++++ 8 files changed, 351 insertions(+), 30 deletions(-) create mode 100644 requirements/release.in create mode 100644 requirements/release.txt create mode 100644 tools/release.py create mode 100644 tools/utils.py diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 72ca6cf28..4bd69c843 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -56,6 +56,12 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Get Salt Project GitHub Actions Bot Environment + run: | + TOKEN=$(curl -sS -f -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 30") + SPB_ENVIRONMENT=$(curl -sS -f -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/tags/instance/spb:environment) + echo "SPB_ENVIRONMENT=$SPB_ENVIRONMENT" >> "$GITHUB_ENV" + - name: Setup GnuPG run: | sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" /run/gpg @@ -86,18 +92,15 @@ jobs: rm "$SECRETS_KEY_FILE" echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Requirements + run: | + python3 -m pip install -r requirements/release.txt + - name: Upload Develop to S3 run: | - echo "Exporting GPG Key" - gpg --output SALT-PROJECT-GPG-PUBKEY-2023.gpg --export 64CBBC8173D76B3F - echo "Exporting Armored GPG Key" - gpg --armor --output SALT-PROJECT-GPG-PUBKEY-2023.pub --export 64CBBC8173D76B3F - declare -a files=("bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub") - for fname in "${files[@]}" - do - echo "GPG Signing ${fpath} ..." - gpg --local-user 64CBBC8173D76B3F --output "${fname}.asc" --armor --detach-sign --sign "${fpath}" - echo "Uploading ${fpath} and ${fpath}.asc to S3" - aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}" - aws s3 cp "${fname}.asc" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/${{ github.ref_name }}/${fname}.asc" - done + tools release s3-publish --key-id 64CBBC8173D76B3F develop diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9c96e20d..2572614bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,7 +65,7 @@ jobs: - name: Install Requirements run: | - python3 -m pip install requests pre-commit + python3 -m pip install -r requirements/release.txt pre-commit install --install-hooks - name: Setup GnuPG @@ -296,9 +296,12 @@ jobs: steps: - uses: actions/checkout@v3 - with: - ref: stable - repository: ${{ github.repository }} + + - name: Get Salt Project GitHub Actions Bot Environment + run: | + TOKEN=$(curl -sS -f -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 30") + SPB_ENVIRONMENT=$(curl -sS -f -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/tags/instance/spb:environment) + echo "SPB_ENVIRONMENT=$SPB_ENVIRONMENT" >> "$GITHUB_ENV" - name: Setup GnuPG run: | @@ -330,16 +333,18 @@ jobs: rm "$SECRETS_KEY_FILE" echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install Requirements + run: | + python3 -m pip install -r requirements/release.txt + - name: Upload Stable Release to S3 run: | - gpg --output SALT-PROJECT-GPG-PUBKEY-2023.gpg --export 64CBBC8173D76B3F - gpg --armor --output SALT-PROJECT-GPG-PUBKEY-2023.pub --export 64CBBC8173D76B3F - files="bootstrap-salt.sh bootstrap-salt.sh.sha256 bootstrap-salt.ps1 bootstrap-salt.ps1.sha256 SALT-PROJECT-GPG-PUBKEY-2023.gpg SALT-PROJECT-GPG-PUBKEY-2023.pub" - for fname in $files; do - gpg --local-user 64CBBC8173D76B3F --output "${fname}.asc" --armor --detach-sign --sign "${fpath}" - aws s3 cp "${fname}" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/stable/${fname}" - aws s3 cp "${fname}.asc" "s3://${{ vars.S3_BUCKET || 'salt-project-prod-salt-artifacts-release' }}/bootstrap/stable/${fname}.asc" - done + tools release s3-publish --key-id 64CBBC8173D76B3F stable update-develop-checksums: name: Update Release Checksums on Develop diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e382ccacc..655876b51 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,11 +16,6 @@ repos: hooks: - id: mdformat - - repo: https://github.com/psf/black - rev: 22.6.0 - hooks: - - id: black - - repo: https://github.com/s0undt3ch/python-tools-scripts rev: "0.12.0" hooks: @@ -34,6 +29,58 @@ repos: - pre-commit - actionlint + - repo: https://github.com/jazzband/pip-tools + rev: 6.13.0 + hooks: + - id: pip-compile + files: ^requirements/release\.(in|txt)$ + args: + - requirements/release.in + + - repo: https://github.com/asottile/pyupgrade + rev: v2.37.3 + hooks: + - id: pyupgrade + name: Rewrite Code to be Py3.9+ + args: [--py39-plus] + + - repo: https://github.com/asottile/reorder_python_imports + rev: v3.8.2 + hooks: + - id: reorder-python-imports + args: [--py39-plus] + + - repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + args: [] + +# - repo: https://github.com/PyCQA/flake8 +# rev: 3.9.2 +# hooks: +# - id: flake8 +# language_version: python3 +# additional_dependencies: +# - flake8-mypy-fork +# - flake8-docstrings +# - flake8-typing-imports +# +# - repo: https://github.com/pre-commit/mirrors-mypy +# rev: v1.0.0 +# hooks: +# - id: mypy +# alias: mypy-tools +# name: Run mypy against tools +# files: ^tools/.*\.py$ +# #args: [--strict] +# additional_dependencies: +# - attrs +# - rich +# - types-attrs +# - types-pyyaml +# - types-requests + - repo: local hooks: - id: generate-actions-workflow diff --git a/requirements/release.in b/requirements/release.in new file mode 100644 index 000000000..d0d1a7378 --- /dev/null +++ b/requirements/release.in @@ -0,0 +1,3 @@ +pre-commit +python-tools-scripts >= 0.12.0 +boto3 diff --git a/requirements/release.txt b/requirements/release.txt new file mode 100644 index 000000000..b4d5a12dd --- /dev/null +++ b/requirements/release.txt @@ -0,0 +1,69 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile requirements/release.in +# +attrs==22.2.0 + # via python-tools-scripts +boto3==1.26.110 + # via -r requirements/release.in +botocore==1.29.110 + # via + # boto3 + # s3transfer +certifi==2022.12.7 + # via requests +cfgv==3.3.1 + # via pre-commit +charset-normalizer==3.1.0 + # via requests +distlib==0.3.6 + # via virtualenv +filelock==3.11.0 + # via virtualenv +identify==2.5.22 + # via pre-commit +idna==3.4 + # via requests +jmespath==1.0.1 + # via + # boto3 + # botocore +markdown-it-py==2.2.0 + # via rich +mdurl==0.1.2 + # via markdown-it-py +nodeenv==1.7.0 + # via pre-commit +platformdirs==3.2.0 + # via virtualenv +pre-commit==3.2.2 + # via -r requirements/release.in +pygments==2.15.0 + # via rich +python-dateutil==2.8.2 + # via botocore +python-tools-scripts==0.12.0 + # via -r requirements/release.in +pyyaml==6.0 + # via pre-commit +requests==2.28.2 + # via python-tools-scripts +rich==13.3.3 + # via python-tools-scripts +s3transfer==0.6.0 + # via boto3 +six==1.16.0 + # via python-dateutil +typing-extensions==4.5.0 + # via python-tools-scripts +urllib3==1.26.15 + # via + # botocore + # requests +virtualenv==20.21.0 + # via pre-commit + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/tools/__init__.py b/tools/__init__.py index f1a241887..4a820ca8f 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -3,6 +3,7 @@ import ptscripts ptscripts.register_tools_module("tools.pre_commit") +ptscripts.register_tools_module("tools.release") for name in ("boto3", "botocore", "urllib3"): logging.getLogger(name).setLevel(logging.INFO) diff --git a/tools/release.py b/tools/release.py new file mode 100644 index 000000000..2b2ee7de7 --- /dev/null +++ b/tools/release.py @@ -0,0 +1,113 @@ +""" +These commands are used to release Salt Bootstrap. +""" +# pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated +from __future__ import annotations + +import logging +import sys +from typing import TYPE_CHECKING + +from ptscripts import command_group +from ptscripts import Context + +import tools.utils + +try: + import boto3 +except ImportError: + print( + "\nPlease run 'python -m pip install -r requirements/release.txt'\n", + file=sys.stderr, + flush=True, + ) + raise + +log = logging.getLogger(__name__) + +# Define the command group +release = command_group( + name="release", + help="Release Related Commands", + description=__doc__, +) + + +@release.command( + name="s3-publish", + arguments={ + "branch": { + "help": "The kind of publish to do.", + "choices": ("stable", "develop"), + }, + "key_id": { + "help": "The GnuPG key ID used to sign.", + "required": True, + }, + }, +) +def s3_publish(ctx: Context, branch: str, key_id: str = None): + """ + Publish scripts to S3. + """ + if TYPE_CHECKING: + assert key_id + + ctx.info("Preparing upload ...") + s3 = boto3.client("s3") + + ctx.info( + f"Uploading release artifacts to {tools.utils.RELEASE_BUCKET_NAME!r} bucket ..." + ) + paths_to_upload = [ + f"{tools.utils.GPG_KEY_FILENAME}.gpg", + f"{tools.utils.GPG_KEY_FILENAME}.pub", + ] + copy_exclusions = [ + ".asc", + ".gpg", + ".pub", + ".sha256", + ] + + try: + # Export the GPG key in use + tools.utils.export_gpg_key(ctx, key_id, tools.utils.REPO_ROOT) + + for fpath in tools.utils.REPO_ROOT.glob("bootstrap-salt.*"): + if fpath.suffix in copy_exclusions: + continue + paths_to_upload.append(fpath.name) + ret = ctx.run( + "sha256sum", + fpath.relative_to(tools.utils.REPO_ROOT), + capture=True, + check=False, + ) + if ret.returncode: + ctx.error( + f"Failed to get the sha256sum of {fpath.relative_to(tools.utils.REPO_ROOT)}" + ) + ctx.exit(1) + shasum_file = fpath.parent / f"{fpath.name}.sha256" + shasum_file.write_bytes(ret.stdout) + paths_to_upload.append(shasum_file.name) + tools.utils.gpg_sign(ctx, key_id, shasum_file) + paths_to_upload.append(f"{shasum_file.name}.asc") + tools.utils.gpg_sign(ctx, key_id, fpath) + paths_to_upload.append(f"{fpath.name}.asc") + + for path in paths_to_upload: + upload_path = f"bootstrap/{branch}/{path}" + size = fpath.stat().st_size + ctx.info(f" {upload_path}") + with tools.utils.create_progress_bar(file_progress=True) as progress: + task = progress.add_task(description="Uploading...", total=size) + s3.upload_file( + fpath, + tools.utils.RELEASE_BUCKET_NAME, + upload_path, + Callback=tools.utils.UpdateProgress(progress, task), + ) + except KeyboardInterrupt: + pass diff --git a/tools/utils.py b/tools/utils.py new file mode 100644 index 000000000..b07beb9bc --- /dev/null +++ b/tools/utils.py @@ -0,0 +1,80 @@ +# pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated +from __future__ import annotations + +import os +import pathlib + +from ptscripts import Context +from rich.progress import BarColumn +from rich.progress import Column +from rich.progress import DownloadColumn +from rich.progress import Progress +from rich.progress import TextColumn +from rich.progress import TimeRemainingColumn +from rich.progress import TransferSpeedColumn + +REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent +GPG_KEY_FILENAME = "SALT-PROJECT-GPG-PUBKEY-2023" +SPB_ENVIRONMENT = os.environ.get("SPB_ENVIRONMENT") or "prod" +RELEASE_BUCKET_NAME = f"salt-project-{SPB_ENVIRONMENT}-salt-artifacts-release" + + +class UpdateProgress: + def __init__(self, progress, task): + self.progress = progress + self.task = task + + def __call__(self, chunk_size): + self.progress.update(self.task, advance=chunk_size) + + +def create_progress_bar(file_progress: bool = False, **kwargs): + if file_progress: + return Progress( + TextColumn("[progress.description]{task.description}"), + BarColumn(), + DownloadColumn(), + TransferSpeedColumn(), + TextColumn("eta"), + TimeRemainingColumn(), + **kwargs, + ) + return Progress( + TextColumn( + "[progress.description]{task.description}", table_column=Column(ratio=3) + ), + BarColumn(), + expand=True, + **kwargs, + ) + + +def export_gpg_key(ctx: Context, key_id: str, export_path: pathlib.Path): + keyfile_gpg = export_path.joinpath(GPG_KEY_FILENAME).with_suffix(".gpg") + if keyfile_gpg.exists(): + keyfile_gpg.unlink() + ctx.info(f"Exporting GnuPG Key '{key_id}' to {keyfile_gpg} ...") + ctx.run("gpg", "--output", str(keyfile_gpg), "--export", key_id) + keyfile_pub = export_path.joinpath(GPG_KEY_FILENAME).with_suffix(".pub") + if keyfile_pub.exists(): + keyfile_pub.unlink() + ctx.info(f"Exporting GnuPG Key '{key_id}' to {keyfile_pub} ...") + ctx.run("gpg", "--armor", "--output", str(keyfile_pub), "--export", key_id) + + +def gpg_sign(ctx: Context, key_id: str, path: pathlib.Path): + ctx.info(f"GPG Signing '{path}' ...") + signature_fpath = path.parent / f"{path.name}.asc" + if signature_fpath.exists(): + signature_fpath.unlink() + ctx.run( + "gpg", + "--local-user", + key_id, + "--output", + str(signature_fpath), + "--armor", + "--detach-sign", + "--sign", + str(path), + ) From c07acc326e8e87471b7b0a122c84e05746c838af Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 14:19:24 +0100 Subject: [PATCH 06/11] Respect the old directory layout Signed-off-by: Pedro Algarvio --- tools/release.py | 110 +++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/tools/release.py b/tools/release.py index 2b2ee7de7..fa703c4c6 100644 --- a/tools/release.py +++ b/tools/release.py @@ -5,6 +5,8 @@ from __future__ import annotations import logging +import os +import pathlib import sys from typing import TYPE_CHECKING @@ -59,54 +61,86 @@ def s3_publish(ctx: Context, branch: str, key_id: str = None): ctx.info( f"Uploading release artifacts to {tools.utils.RELEASE_BUCKET_NAME!r} bucket ..." ) - paths_to_upload = [ - f"{tools.utils.GPG_KEY_FILENAME}.gpg", - f"{tools.utils.GPG_KEY_FILENAME}.pub", - ] - copy_exclusions = [ - ".asc", - ".gpg", - ".pub", - ".sha256", - ] + upload_files = { + "stable": { + f"{tools.utils.GPG_KEY_FILENAME}.gpg": [ + f"bootstrap/stable/{tools.utils.GPG_KEY_FILENAME}.gpg", + ], + f"{tools.utils.GPG_KEY_FILENAME}.pub": [ + f"bootstrap/stable/{tools.utils.GPG_KEY_FILENAME}.pub", + ], + "bootstrap-salt.sh": [ + "bootstrap/stable/bootstrap-salt.sh", + ], + "bootstrap-salt.sh.sha256": [ + "bootstrap/stable/bootstrap-salt.sh.sha256", + "bootstrap/stable/bootstrap/sha256", + ], + "bootstrap-salt.ps1": [ + "bootstrap/stable/bootstrap-salt.ps1", + ], + "bootstrap-salt.ps1.sha256": [ + "bootstrap/stable/bootstrap-salt.ps1.sha256", + "bootstrap/stable/winbootstrap/sha256", + ], + }, + "develop": { + f"{tools.utils.GPG_KEY_FILENAME}.gpg": [ + f"bootstrap/develop/{tools.utils.GPG_KEY_FILENAME}.gpg", + ], + f"{tools.utils.GPG_KEY_FILENAME}.pub": [ + f"bootstrap/develop/{tools.utils.GPG_KEY_FILENAME}.pub", + ], + "bootstrap-salt.sh": [ + "bootstrap/develop/bootstrap-salt.sh", + "bootstrap/develop/bootstrap/develop", + ], + "bootstrap-salt.sh.sha256": [ + "bootstrap/develop/bootstrap-salt.sh.sha256", + ], + "bootstrap-salt.ps1": [ + "bootstrap/develop/bootstrap-salt.ps1", + "bootstrap/develop/winbootstrap/develop", + ], + "bootstrap-salt.ps1.sha256": [ + "bootstrap/develop/bootstrap-salt.ps1.sha256", + ], + }, + } + + files_to_upload: list[tuple[str, str]] = [] try: # Export the GPG key in use tools.utils.export_gpg_key(ctx, key_id, tools.utils.REPO_ROOT) - - for fpath in tools.utils.REPO_ROOT.glob("bootstrap-salt.*"): - if fpath.suffix in copy_exclusions: - continue - paths_to_upload.append(fpath.name) - ret = ctx.run( - "sha256sum", - fpath.relative_to(tools.utils.REPO_ROOT), - capture=True, - check=False, - ) - if ret.returncode: - ctx.error( - f"Failed to get the sha256sum of {fpath.relative_to(tools.utils.REPO_ROOT)}" + for lpath, rpaths in upload_files[branch].items(): + ctx.info(f"Processing {lpath} ...") + if lpath.endswith(".sha256") and not os.path.exists(lpath): + ret = ctx.run( + "sha256sum", + lpath.replace(".sha256", ""), + capture=True, + check=False, ) - ctx.exit(1) - shasum_file = fpath.parent / f"{fpath.name}.sha256" - shasum_file.write_bytes(ret.stdout) - paths_to_upload.append(shasum_file.name) - tools.utils.gpg_sign(ctx, key_id, shasum_file) - paths_to_upload.append(f"{shasum_file.name}.asc") - tools.utils.gpg_sign(ctx, key_id, fpath) - paths_to_upload.append(f"{fpath.name}.asc") + if ret.returncode: + ctx.error(f"Failed to get the sha256sum of {lpath}") + ctx.exit(1) + pathlib.Path(lpath).write_bytes(ret.stdout) + for rpath in rpaths: + files_to_upload.append((lpath, rpath)) + if not lpath.endswith((".gpg", ".pub")): + tools.utils.gpg_sign(ctx, key_id, pathlib.Path(lpath)) + files_to_upload.append((f"{lpath}.asc", f"{rpaths[0]}.asc")) - for path in paths_to_upload: - upload_path = f"bootstrap/{branch}/{path}" - size = fpath.stat().st_size - ctx.info(f" {upload_path}") + for lpath, rpath in sorted(files_to_upload): + size = pathlib.Path(lpath).stat().st_size + ctx.info(f" Uploading {lpath} -> {rpath}") with tools.utils.create_progress_bar(file_progress=True) as progress: task = progress.add_task(description="Uploading...", total=size) s3.upload_file( - fpath, + lpath, tools.utils.RELEASE_BUCKET_NAME, - upload_path, + rpath, Callback=tools.utils.UpdateProgress(progress, task), ) except KeyboardInterrupt: From 0184635370363927e0de35dc8823116cdbea8d11 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 14:24:59 +0100 Subject: [PATCH 07/11] Use the installed python on the runners Signed-off-by: Pedro Algarvio --- .github/workflows/nightly.yml | 5 ----- .github/workflows/release.yml | 15 --------------- 2 files changed, 20 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4bd69c843..d04378611 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -92,11 +92,6 @@ jobs: rm "$SECRETS_KEY_FILE" echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Install Requirements run: | python3 -m pip install -r requirements/release.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2572614bf..7734c9dcf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,11 +58,6 @@ jobs: repository: ${{ github.repository }} ssh-key: ${{ secrets.SALT_BOOTSTRAP_RELEASE_KEY }} - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Install Requirements run: | python3 -m pip install -r requirements/release.txt @@ -333,11 +328,6 @@ jobs: rm "$SECRETS_KEY_FILE" echo "passphrase-file ${GNUPGHOME}/passphrase" >> "${GNUPGHOME}/gpg.conf" - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Install Requirements run: | python3 -m pip install -r requirements/release.txt @@ -416,11 +406,6 @@ jobs: git config --global user.signingkey 64CBBC8173D76B3F git config --global commit.gpgsign true - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - name: Update Latest Release on README run: | python3 .github/workflows/scripts/update-release-shasum.py ${{ env.BS_VERSION }} ${{ env.SH }} From 2a4f2ad3f66ac169192df94d9a2296fe7e7fee68 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 14:37:32 +0100 Subject: [PATCH 08/11] Allow testing releases from forks Signed-off-by: Pedro Algarvio --- .github/workflows/release.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7734c9dcf..211a8eb5b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,13 +17,25 @@ jobs: - name: Check Repository run: | + if [ "${{ vars.RUN_RELEASE_BUILDS }}" = "1" ]; then + MSG="Running workflow because RUN_RELEASE_BUILDS=1" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + exit 0 + fi echo "Trying to run the release workflow from repository ${{ github.repository }}" if [ "${{ github.repository }}" != "saltstack/salt-bootstrap" ]; then - echo "Running the release workflow from the ${{ github.repository }} repository is not allowed" - echo "Allowed repository: saltstack/salt-bootstrap" + MSG="Running the release workflow from the ${{ github.repository }} repository is not allowed" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + MSG="Allowed repository: saltstack/salt-bootstrap" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" exit 1 else - echo "Allowed to release from repository ${{ github.repository }}" + MSG="Allowed to release from repository ${{ github.repository }}" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" fi - name: Check Branch From 3d3c7c7a9fbeb0d823696841fb3c6437e862b0df Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 15:25:31 +0100 Subject: [PATCH 09/11] Fix opening PR against the Salt repository Signed-off-by: Pedro Algarvio --- .github/workflows/release.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 211a8eb5b..f89df8949 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -514,6 +514,11 @@ jobs: run: | cp bootstrap-salt.sh salt-checkout/salt/cloud/deploy/bootstrap-salt.sh + - name: Commit Changes + working-directory: salt-checkout/ + run: | + git commit -am "Update the bootstrap script to v${{ env.BS_VERSION }}" + - name: Create Pull Request Against Develop uses: peter-evans/create-pull-request@v5 with: @@ -521,7 +526,8 @@ jobs: path: salt-checkout base: master token: ${{ secrets.SALT_REPO_WRITE_TOKEN }} + author: "Salt Project Packaging " + committer: "Salt Project Packaging " commit-message: Update the bootstrap script to v${{ env.BS_VERSION }} + signoff: true delete-branch: true - add-paths: | - salt-checkout/salt/cloud/deploy/bootstrap-salt.sh From 6c6291bdd593d5c71ca038a1abaa4ca5df5e086e Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 15:40:46 +0100 Subject: [PATCH 10/11] Don't rely on GH runners during the release process once started. Signed-off-by: Pedro Algarvio --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f89df8949..b6d8f219e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -246,7 +246,9 @@ jobs: publish-release: name: Create GitHub Release - runs-on: ubuntu-latest + runs-on: + - self-hosted + - linux needs: - merge-develop-into-stable environment: release From ce4a0719430bff9021dec328f35ee91bf56be4ef Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 12 Apr 2023 15:42:17 +0100 Subject: [PATCH 11/11] Bump to `geekyeggo/delete-artifact@v2` Signed-off-by: Pedro Algarvio --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6d8f219e..05c8c43d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -288,7 +288,7 @@ jobs: LICENSE - name: Delete Release Details Artifact - uses: geekyeggo/delete-artifact@v1 + uses: geekyeggo/delete-artifact@v2 with: name: release-details failOnError: false