name: Helm Release on: workflow_call: inputs: release-tag: description: "Release tag, for example v0.2.0" required: true type: string secrets: token: required: true HELM_OCI_REPOSITORY: required: false DOCKERHUB_USERNAME: required: false DOCKERHUB_REPOSITORY: required: false DOCKERHUB_PASSWORD: required: false permissions: contents: read packages: write jobs: publish: name: Publish Helm Chart runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v5 with: fetch-depth: 0 - name: Set up Helm uses: azure/setup-helm@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@nightly - name: Install protobuf compiler run: sudo apt-get update && sudo apt-get install -y protobuf-compiler - name: Read chart metadata id: chart shell: bash env: RELEASE_TAG: ${{ inputs.release-tag }} GHCR_REPOSITORY: ${{ github.repository }} HELM_OCI_REPOSITORY: ${{ vars.HELM_OCI_REPOSITORY || secrets.HELM_OCI_REPOSITORY }} DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME || secrets.DOCKERHUB_USERNAME }} DOCKERHUB_REPOSITORY: ${{ vars.DOCKERHUB_REPOSITORY || secrets.DOCKERHUB_REPOSITORY }} run: | chart_name="$(ruby -ryaml -e 'puts YAML.load_file(ARGV.fetch(0)).fetch("name")' helm/synctv/Chart.yaml)" chart_version="$(ruby -ryaml -e 'puts YAML.load_file(ARGV.fetch(0)).fetch("version")' helm/synctv/Chart.yaml)" app_version="$(ruby -ryaml -e 'puts YAML.load_file(ARGV.fetch(0)).fetch("appVersion")' helm/synctv/Chart.yaml)" cargo_version="$(make -s cargo-workspace-version)" if [ -z "$chart_name" ] || [ -z "$chart_version" ] || [ -z "$app_version" ] || [ -z "$cargo_version" ]; then echo "Chart.yaml must define name, version, and appVersion; Cargo.toml must define workspace.package.version." >&2 exit 1 fi tag_version="${RELEASE_TAG#v}" if [ "$chart_version" != "$tag_version" ]; then echo "Chart version ($chart_version) must match release tag ($tag_version)." >&2 exit 1 fi if [ "$app_version" != "$tag_version" ]; then echo "Chart appVersion ($app_version) must match release tag ($tag_version)." >&2 exit 1 fi if [ "$cargo_version" != "$tag_version" ]; then echo "Cargo workspace version ($cargo_version) must match release tag ($tag_version)." >&2 exit 1 fi repo="$(printf '%s' "${GITHUB_REPOSITORY#*/}" | tr '[:upper:]' '[:lower:]')" if [ -n "$DOCKERHUB_REPOSITORY" ]; then case "$DOCKERHUB_REPOSITORY" in */*) dockerhub_repository="$DOCKERHUB_REPOSITORY" ;; *) dockerhub_repository="$DOCKERHUB_USERNAME/$DOCKERHUB_REPOSITORY" ;; esac elif [ -n "$DOCKERHUB_USERNAME" ]; then dockerhub_repository="$DOCKERHUB_USERNAME/$repo" fi { echo "name=$chart_name" echo "version=$chart_version" echo "app_version=$app_version" echo "dockerhub_username=$DOCKERHUB_USERNAME" echo 'oci_repos<> "$GITHUB_OUTPUT" - name: Set release image repository env: PUBLISH_IMAGE_REPOSITORY: ${{ github.repository }} run: | ruby <<'RUBY' require "yaml" path = "helm/synctv/values.yaml" values = YAML.load_file(path) image = values.fetch("image") image["registry"] = "ghcr.io" image["repository"] = ENV.fetch("PUBLISH_IMAGE_REPOSITORY").downcase File.write(path, YAML.dump(values)) puts "OCI release image: #{image['registry']}/#{image['repository']}" RUBY - name: Validate chart run: make validate-helm - name: Package chart run: | mkdir -p dist helm package ./helm/synctv --destination dist - name: Login to GHCR run: echo "${{ secrets.token }}" | helm registry login ghcr.io --username "$GITHUB_ACTOR" --password-stdin - name: Login to Docker Hub if: steps.chart.outputs.dockerhub_username != '' env: DOCKERHUB_USERNAME: ${{ steps.chart.outputs.dockerhub_username }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} run: echo "$DOCKERHUB_PASSWORD" | helm registry login docker.io --username "$DOCKERHUB_USERNAME" --password-stdin - name: Push chart to OCI registries shell: bash run: | while IFS= read -r oci_repo; do if [ -z "$oci_repo" ]; then continue fi check_dir="$(mktemp -d)" if helm pull "oci://$oci_repo/${{ steps.chart.outputs.name }}" \ --version "${{ steps.chart.outputs.version }}" \ --destination "$check_dir" >/dev/null 2>&1; then echo "OCI chart $oci_repo/${{ steps.chart.outputs.name }}:${{ steps.chart.outputs.version }} already exists; skipping push." continue fi helm push "dist/${{ steps.chart.outputs.name }}-${{ steps.chart.outputs.version }}.tgz" \ "oci://$oci_repo" done <<'EOF' ${{ steps.chart.outputs.oci_repos }} EOF