diff --git a/release.sh b/release.sh deleted file mode 100755 index 3125839..0000000 --- a/release.sh +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/bash - -set -e - -if [ -z "$1" ]; then - echo "Usage: $0 " - exit 1 -fi - -tools=("helm-docs" "gh" "yq" "git-cliff" "git" "curl" "awk" "sed") - -for tool in "${tools[@]}"; do - if ! command -v "$tool" >/dev/null 2>&1; then - echo "❌ $tool is missing. See README.md for all required tools" - exit 1 - fi -done - -ISSUE_LINK=$1 -VECTOR_VERSION=$(curl --silent https://api.github.com/repos/vectordotdev/vector/releases/latest \ - | grep -oE "tag_name\": *\".{1,15}\"," \ - | ${SED:-sed} 's/tag_name\": *\"v//;s/\",//') - -create_pr() { - local branch title output pr_url - branch="$1" - title="$2" - body="${3:-Ref: $ISSUE_LINK}" - - output=$(gh pr create \ - --title "$title" \ - --body "$body" \ - --base develop --head "$branch") - - pr_url=$(echo "$output" | tail -n 1) - echo "$pr_url" -} - -green() { - printf '\033[32m%s\033[0m\n' "$1" -} - -purple() { - printf '\033[35m%s\033[0m\n' "$1" -} - -wait_for_pr_merge() { - local pr_url="$1" - - echo "Waiting for PR ($pr_url) to be merged..." - - while [[ -z $(gh pr view "$pr_url" --json mergedAt -q .mergedAt) ]]; do - sleep 10 - done - - purple "PR ($pr_url) has been merged!" -} - -# Ensure we are on the develop branch -git switch develop -git pull - -# Step 1: Run .github/release-vector-version.sh -BRANCH1="update-vector-version-$VECTOR_VERSION" -git checkout -b "$BRANCH1" -.github/release-vector-version.sh - -# Step 2: Update Helm docs -helm-docs - -# Commit changes from Steps 1 and 2 -if [ -n "$(git status --porcelain)" ]; then - git add . - git commit -m \ - "feat(vector): Bump Vector to $VECTOR_VERSION and update Helm docs" - echo "Committed changes from Steps 1 and 2." - git push -u origin "$BRANCH1" -else - echo "No changes to commit from Steps 1 and 2." - exit 1 -fi - -# Push the branch and submit a PR for Steps 1 and 2 -PR1_URL=$(create_pr "$BRANCH1" "feat(releasing): Update Vector version to $VECTOR_VERSION and Helm docs") -green "PR for Steps 1 & 2 submitted: $PR1_URL" -wait_for_pr_merge "$PR1_URL" - -# Step 3: Run .github/release-changelog.sh -git switch develop -git pull - -BRANCH2="regenerate-changelog-$VECTOR_VERSION" -git checkout -b "$BRANCH2" -.github/release-changelog.sh - -# Commit changes from Step 3 -if [ -n "$(git status --porcelain)" ]; then - git add . - git commit -m \ - "feat(vector): Regenerate CHANGELOG for $VECTOR_VERSION" - echo "Committed changes from Step 3." - git push -u origin "$BRANCH2" -else - echo "No changes to commit from Step 3." - exit 1 -fi - -# Push the branch and submit a PR for Step 3 -CHART_VERSION=$(awk -F': ' '/version:/ {gsub(/"/, "", $2); print $2}' charts/vector/Chart.yaml) -PR2_URL=$(create_pr "$BRANCH2" "chore(vector): Regenerate CHANGELOG for $CHART_VERSION") -green "PR for Step 3 submitted: $PR2_URL" - -# Both PRs needs to be merged before updating the master branch. -wait_for_pr_merge "$PR2_URL" - -# Final Step: Merge develop into master -git fetch -git switch master -git pull -git merge develop -git push - -echo "Release workflow initiated: https://github.com/vectordotdev/helm-charts/actions/workflows/release.yaml" - -# Post Release Step -git switch develop -NEW_CHART_VERSION=$(echo "$CHART_VERSION" | awk -F. '{ $2++; $3=0; print $1"."$2"."$3 }') -BRANCH3="bump-chart-version-$NEW_CHART_VERSION" - -git checkout -b "$BRANCH3" - -# MacOS sed doesn't support -i like all other implementations do -sed "/^version:/s|$CHART_VERSION|$NEW_CHART_VERSION|" charts/vector/Chart.yaml > charts/vector/Chart.yaml.tmp \ - && mv charts/vector/Chart.yaml.tmp charts/vector/Chart.yaml - - -# Update Helm docs -helm-docs - -message="chore(releasing): Bump chart version to $NEW_CHART_VERSION" - -# Commit changes from Post Release Step -if [ -n "$(git status --porcelain)" ]; then - git add . - git commit -m "$message" - echo "Committed changes from Post Release Step" - git push -u origin "$BRANCH3" -else - echo "No changes to commit from Post Release Step" - exit 1 -fi - -PR3_URL=$(create_pr "$BRANCH3" "$message" "Post release version bump") -green "Post Release Step PR submitted: $PR3_URL" - -wait_for_pr_merge "$PR3_URL" - -echo "Make sure to monitor the release workflow if you aren't already: https://github.com/vectordotdev/helm-charts/actions/workflows/release.yaml" diff --git a/release/.gitignore b/release/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/release/.gitignore @@ -0,0 +1 @@ +/target diff --git a/release/Cargo.lock b/release/Cargo.lock new file mode 100644 index 0000000..3747c25 --- /dev/null +++ b/release/Cargo.lock @@ -0,0 +1,678 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "helm-release" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "ureq", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/release/Cargo.toml b/release/Cargo.toml new file mode 100644 index 0000000..380ea7d --- /dev/null +++ b/release/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "helm-release" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "helm-release" +path = "src/main.rs" + +[dependencies] +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +ureq = { version = "2", features = ["json"] } diff --git a/release/src/main.rs b/release/src/main.rs new file mode 100644 index 0000000..a690815 --- /dev/null +++ b/release/src/main.rs @@ -0,0 +1,370 @@ +use anyhow::{bail, Context, Result}; +use serde::{Deserialize, Serialize}; +use std::{fs, process::Command, thread, time::Duration}; + +const STATE_FILE: &str = ".release-state.json"; +const GITHUB_API: &str = + "https://api.github.com/repos/vectordotdev/vector/releases/latest"; +const POLL_INTERVAL: Duration = Duration::from_secs(10); + +/// Each variant is a stable checkpoint. The program saves state *after* completing +/// all work for a phase, so resuming always re-enters at a clean boundary. +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "phase")] +enum Phase { + /// Nothing done yet. Fetch version, create version-bump branch/PR. + FetchVersion { issue_link: String }, + + /// Version-bump PR created. Waiting for it to merge, then run changelog. + WaitForVersionPr { + issue_link: String, + vector_version: String, + pr_url: String, + }, + + /// Changelog PR created. Waiting for it to merge, then merge to master. + WaitForChangelogPr { + issue_link: String, + vector_version: String, + chart_version: String, + pr_url: String, + }, + + /// Post-release version-bump PR created. Waiting for it to merge. + WaitForBumpPr { + issue_link: String, + new_chart_version: String, + pr_url: String, + }, + + Done, +} + +fn issue_link_of(phase: &Phase) -> Option<&str> { + match phase { + Phase::FetchVersion { issue_link } => Some(issue_link), + Phase::WaitForVersionPr { issue_link, .. } => Some(issue_link), + Phase::WaitForChangelogPr { issue_link, .. } => Some(issue_link), + Phase::WaitForBumpPr { issue_link, .. } => Some(issue_link), + Phase::Done => None, + } +} + +// ── state file ─────────────────────────────────────────────────────────────── + +fn load_state() -> Option { + let content = fs::read_to_string(STATE_FILE).ok()?; + serde_json::from_str(&content).ok() +} + +fn save_state(phase: &Phase) -> Result<()> { + fs::write(STATE_FILE, serde_json::to_string_pretty(phase)?)?; + Ok(()) +} + +// ── shell helpers ───────────────────────────────────────────────────────────── + +/// Run a command, inheriting stdout/stderr. Fails if exit code is non-zero. +fn run(program: &str, args: &[&str]) -> Result<()> { + let status = Command::new(program) + .args(args) + .status() + .with_context(|| format!("failed to spawn `{program}`"))?; + if !status.success() { + bail!("`{program} {}` exited with {status}", args.join(" ")); + } + Ok(()) +} + +/// Run a command, capturing stdout. Fails if exit code is non-zero. +fn run_capture(program: &str, args: &[&str]) -> Result { + let output = Command::new(program) + .args(args) + .output() + .with_context(|| format!("failed to spawn `{program}`"))?; + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + bail!("`{program} {}` failed: {stderr}", args.join(" ")); + } + Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) +} + +fn check_tool(tool: &str) -> Result<()> { + let ok = Command::new("sh") + .args(["-c", &format!("command -v {tool}")]) + .status() + .map(|s| s.success()) + .unwrap_or(false); + if !ok { + bail!("❌ {tool} is missing. See README.md for all required tools"); + } + Ok(()) +} + +// ── domain helpers ──────────────────────────────────────────────────────────── + +fn fetch_vector_version() -> Result { + let response = ureq::get(GITHUB_API) + .set("User-Agent", "helm-release") + .call() + .context("failed to fetch latest Vector release from GitHub")?; + let json: serde_json::Value = response.into_json()?; + let tag = json["tag_name"] + .as_str() + .context("tag_name missing from GitHub API response")?; + Ok(tag.trim_start_matches('v').to_string()) +} + +fn read_chart_version() -> Result { + let content = fs::read_to_string("charts/vector/Chart.yaml") + .context("failed to read charts/vector/Chart.yaml")?; + for line in content.lines() { + if let Some(rest) = line.strip_prefix("version:") { + return Ok(rest.trim().trim_matches('"').to_string()); + } + } + bail!("version field not found in charts/vector/Chart.yaml") +} + +fn bump_minor(version: &str) -> Result { + let parts: Vec<&str> = version.split('.').collect(); + if parts.len() != 3 { + bail!("unexpected version format: {version}"); + } + let major: u32 = parts[0].parse().context("invalid major version")?; + let minor: u32 = parts[1].parse().context("invalid minor version")?; + Ok(format!("{major}.{}.0", minor + 1)) +} + +fn bump_chart_yaml(old: &str, new: &str) -> Result<()> { + let path = "charts/vector/Chart.yaml"; + let content = fs::read_to_string(path)?; + let old_line = format!("version: \"{old}\""); + let new_line = format!("version: \"{new}\""); + if !content.contains(&old_line) { + bail!("could not find `{old_line}` in {path}"); + } + fs::write(path, content.replacen(&old_line, &new_line, 1))?; + Ok(()) +} + +fn create_pr(branch: &str, title: &str, body: &str) -> Result { + let output = run_capture( + "gh", + &[ + "pr", "create", + "--title", title, + "--body", body, + "--base", "develop", + "--head", branch, + ], + )?; + output + .lines() + .filter(|l| !l.is_empty()) + .last() + .map(|s| s.to_string()) + .context("no output from `gh pr create`") +} + +fn wait_for_merge(pr_url: &str) -> Result<()> { + println!("Waiting for PR ({pr_url}) to be merged..."); + loop { + let merged_at = run_capture( + "gh", + &["pr", "view", pr_url, "--json", "mergedAt", "-q", ".mergedAt"], + )?; + if !merged_at.is_empty() && merged_at != "null" { + println!("\x1b[35mPR ({pr_url}) has been merged!\x1b[0m"); + return Ok(()); + } + thread::sleep(POLL_INTERVAL); + } +} + +// ── state machine ───────────────────────────────────────────────────────────── + +fn step(phase: Phase) -> Result { + match phase { + Phase::FetchVersion { issue_link } => { + let vector_version = fetch_vector_version()?; + println!("Latest Vector version: {vector_version}"); + + let branch = format!("update-vector-version-{vector_version}"); + + // Step 1 & 2: version bump + helm-docs + run("git", &["switch", "develop"])?; + run("git", &["pull"])?; + run("git", &["checkout", "-b", &branch])?; + run(".github/release-vector-version.sh", &[])?; + run("helm-docs", &[])?; + + if run_capture("git", &["status", "--porcelain"])?.is_empty() { + bail!("no changes to commit from Steps 1 and 2"); + } + run("git", &["add", "."])?; + run( + "git", + &[ + "commit", "-m", + &format!("feat(vector): Bump Vector to {vector_version} and update Helm docs"), + ], + )?; + run("git", &["push", "-u", "origin", &branch])?; + + let pr_url = create_pr( + &branch, + &format!( + "feat(releasing): Update Vector version to {vector_version} and Helm docs" + ), + &format!("Ref: {issue_link}"), + )?; + println!("\x1b[32mPR for Steps 1 & 2 submitted: {pr_url}\x1b[0m"); + + Ok(Phase::WaitForVersionPr { + issue_link, + vector_version, + pr_url, + }) + } + + Phase::WaitForVersionPr { + issue_link, + vector_version, + pr_url, + } => { + wait_for_merge(&pr_url)?; + + // Step 3: changelog + run("git", &["switch", "develop"])?; + run("git", &["pull"])?; + + let branch = format!("regenerate-changelog-{vector_version}"); + run("git", &["checkout", "-b", &branch])?; + run(".github/release-changelog.sh", &[])?; + + if run_capture("git", &["status", "--porcelain"])?.is_empty() { + bail!("no changes to commit from Step 3"); + } + run("git", &["add", "."])?; + run( + "git", + &[ + "commit", "-m", + &format!("feat(vector): Regenerate CHANGELOG for {vector_version}"), + ], + )?; + run("git", &["push", "-u", "origin", &branch])?; + + let chart_version = read_chart_version()?; + let pr_url = create_pr( + &branch, + &format!("chore(vector): Regenerate CHANGELOG for {chart_version}"), + &format!("Ref: {issue_link}"), + )?; + println!("\x1b[32mPR for Step 3 submitted: {pr_url}\x1b[0m"); + + Ok(Phase::WaitForChangelogPr { + issue_link, + vector_version, + chart_version, + pr_url, + }) + } + + Phase::WaitForChangelogPr { + issue_link, + vector_version: _, + chart_version, + pr_url, + } => { + wait_for_merge(&pr_url)?; + + // Final step: merge develop → master + run("git", &["fetch"])?; + run("git", &["switch", "master"])?; + run("git", &["pull"])?; + run("git", &["merge", "develop"])?; + run("git", &["push"])?; + println!("Release workflow initiated: https://github.com/vectordotdev/helm-charts/actions/workflows/release.yaml"); + + // Post-release: bump chart version + run("git", &["switch", "develop"])?; + let new_chart_version = bump_minor(&chart_version)?; + let branch = format!("bump-chart-version-{new_chart_version}"); + run("git", &["checkout", "-b", &branch])?; + + bump_chart_yaml(&chart_version, &new_chart_version)?; + run("helm-docs", &[])?; + + if run_capture("git", &["status", "--porcelain"])?.is_empty() { + bail!("no changes to commit from Post Release Step"); + } + let message = format!("chore(releasing): Bump chart version to {new_chart_version}"); + run("git", &["add", "."])?; + run("git", &["commit", "-m", &message])?; + run("git", &["push", "-u", "origin", &branch])?; + + let pr_url = create_pr(&branch, &message, "Post release version bump")?; + println!("\x1b[32mPost Release Step PR submitted: {pr_url}\x1b[0m"); + + Ok(Phase::WaitForBumpPr { + issue_link, + new_chart_version, + pr_url, + }) + } + + Phase::WaitForBumpPr { pr_url, .. } => { + wait_for_merge(&pr_url)?; + Ok(Phase::Done) + } + + Phase::Done => Ok(Phase::Done), + } +} + +// ── main ────────────────────────────────────────────────────────────────────── + +fn main() -> Result<()> { + let issue_link = std::env::args() + .nth(1) + .context("Usage: helm-release ")?; + + for tool in &["helm-docs", "gh", "yq", "git-cliff", "git", "curl"] { + check_tool(tool)?; + } + + let mut phase = match load_state() { + Some(Phase::Done) => { + println!("Release already complete. Remove {STATE_FILE} to start a new release."); + fs::remove_file(STATE_FILE).ok(); + return Ok(()); + } + Some(p) if issue_link_of(&p) == Some(issue_link.as_str()) => { + println!("\x1b[35mResuming release from saved state...\x1b[0m"); + p + } + Some(_) => { + bail!( + "State file {STATE_FILE} belongs to a different release. \ + Remove it to start fresh." + ); + } + None => Phase::FetchVersion { issue_link }, + }; + + loop { + let next = step(phase)?; + if matches!(next, Phase::Done) { + fs::remove_file(STATE_FILE).ok(); + println!("Make sure to monitor the release workflow if you aren't already:"); + println!("https://github.com/vectordotdev/helm-charts/actions/workflows/release.yaml"); + break; + } + save_state(&next)?; + phase = next; + } + + Ok(()) +}