Helm chart hooks can do this. There's a series of points where Helm can deploy a set of resources one at a time and wait for them to be ready or completed.
For what you're describing, it is enough to use an annotation to mark a job as a pre-install hook:
apiVersion: batch/v1
kind: Job
metadata:
annotations:
"helm.sh/hook": pre-install
None of the other resources in the chart will be deployed until the hook executes successfully. If the Job fails, it will block deploying any other resources. This pre-install
hook only runs on first installation, but if you want the hook to run on upgrades or rollbacks, there are corresponding hooks to be able to do this.
There are still some workflows that are hard to express this way. For instance, if your service includes a database and you want a job to run migrations or seed data, you can't really deploy the database StatefulSet, then block on a Job hook, then deploy everything else; your application still needs to tolerate things maybe not being in the exact state it expects.