Repository navigation
Unexpected failure with version command #1046
Description
Activity
- addedtriagewaiting for initial maintainer reviewwaiting for initial maintainer review
on Oct 1, 2024 Hi @clarkecheckr, the primary issue is actually right there on line 142. You are in a detached head state. Because of this, we cannot determine which release branch configuration to use and therefore we give up (not ideal, I know but the best I have at the moment).
GitLab uses a detached head state in the way they checkout a small git tree to make it faster to execute the pipelines as most do not need the entire git tree. PSR does need the full git tree as well as being checked out to a specific branch.
My recommendation is you should run the following:
# make sure you have the full accurate history git fetch --unshallow --prune-tags --prune --all --force # make sure the branch Head is at the commit that was tested/started the workflow git checkout -B $CI_COMMIT_BRANCH HEAD semantic-release -vv version
I'm working on a repo that is just for getting this working in Gitlab and have an absolute minimal configuration for psr. I'd like to contribute my working .gitlab-ci.yml and pyproject.toml configuration to be used as an example in the docs as they would have helped me out immensely. How would I go about that?
I'm not sure how it isn't a problem in your branch environment as a detached head state is an immediate abort for semantic release
It's not a detached head, it's just the same message that the branch isn't in any release groups.
Well that message is at the exact same part of the code, it is also an immediate abort. It succeeds though because it is not in
--strictmode.I'm working on a repo that is just for getting this working in Gitlab and have an absolute minimal configuration for psr. I'd like to contribute my working .gitlab-ci.yml and pyproject.toml configuration to be used as an example in the docs as they would have helped me out immensely. How would I go about that?
Generally for a GitHub contribution, you would fork the repository, create a branch on your fork, make your changes and then open a PR from your fork's branch to this repo's master branch. The docs are in the docs folder. Review the Contributors.rst as well for info about how to build the docs and general info.
However, I have a GitLab instruction guide in the works (70% complete) but I haven't published it yet. Ultimately I will have an examples section in that area like I do for github-actions (docs/automatic-releases/github-actions.rst).
If you want to just put your examples in a gitlab.rst in that folder and explain the rationale, then I will fold yours into my format.
BTW,
git checkout -B $CI_COMMIT_BRANCHfails with the errorfatal: 'HEAD' is not a valid branch name. I get the idea and I'm looking up a way to do it.The reason this is happening on the tag creation is that the value of
$CI_COMMIT_BRANCHis "", so the command readsgit checkout -B HEADand that's not valid. I tried to add a rule to the .gitlab-ci.yml, but then my pipeline didn't run at all, so I have a little work to do to figure this out.Adding a rule to skip the pipeline if
$CI_COMMIT_BRANCHis null kinda worked, but now I'm not creating a tag. I thought maybe it would create the tag, just not run the pipeline but that's not the case.stages: - release variables: GITLAB_TOKEN: $gitlab_pat release: stage: release image: python:latest before_script: - pip install python-semantic-release script: - git fetch --unshallow --prune-tags --prune --all --force - git checkout -B $CI_COMMIT_BRANCH HEAD - semantic-release -v version rules: - if: $CI_COMMIT_BRANCH != nullI was able to get this working with the following config. The reason it was failing when using
git checkout -B $CI_COMMIT_BRANCH HEADwas because when we get to the tag creation step the value of$CI_COMMIT_BRANCHis null. The following config checks to see if it's null, if it is then we set the variable to$CI_COMMIT_REF_NAMEotherwise we use$CI_COMMIT_BRANCH. This seems to work but I will be testing it more to confirm. Can you see anything wrong with this method?stages: - release variables: GITLAB_TOKEN: $gitlab_pat release: stage: release image: python:latest before_script: - pip install python-semantic-release script: - git fetch --unshallow --prune-tags --prune --all --force - echo "CI_COMMIT_REF_NAME" $CI_COMMIT_REF_NAME - git checkout -B $SOURCE_BRANCH HEAD - semantic-release -v version rules: # if the commit branch is not null, use the commit branch name - if: $CI_COMMIT_BRANCH != null variables: SOURCE_BRANCH: $CI_COMMIT_BRANCH # if the commit branch is null, use the commit ref name # this is to account for the fact that the version tag has a null value for $CI_COMMIT_BRANCH - if: $CI_COMMIT_BRANCH == null variables: SOURCE_BRANCH: $CI_COMMIT_REF_NAME@clarkecheckr, sorry I was unavailable while you worked the issue.
There isn't anything particularly wrong with your approach but I can't say it would be my way I would solve the problem. I will try to provide some conceptual rationale behind my approach first. In my solution, I utilize
workflow:rulesto restrict the types of pipelines that occur. I generally recommend to never run semantic-release on a tag triggered pipeline. This defeats the purpose of usingsemantic-release. The idea behind PSR and conventional commit strategies is to eliminate the emotional attachment to release versions, which crudely means no human makes a tag anymore--PSR handles that based on what you documented that changed. Secondly, I think its a bit of a waste of resources to spin up another pipeline which has no comprehension of what was accomplished prior to the tagged release and rather just set a deploy stage (set of deploy jobs, many times there is more than one deployment target) that is dependent on release job outcomes.Also note, that I generally use GitHub Flow branching strategy coupled with a Squash commit merge strategy and in my projects, I rarely create pre-releases (more of a result of my environment, but small amount of preference). Lastly, I haven't done too much of multi-version release support (ie v2 in maintenance, v3 is stable, v4 is unstable) so my example below doesn't handle this.
So in my workflows, I run when there is a (1) push to the default branch, (2) a merge request event, (3) a pipeline source that is manual or deliberately triggered. Regardless of the workflow trigger, I run a check stage that simultaneously runs a build, code linting, commit-linting, unit testing. Then I move into a test stage which focuses on runtime (system, integration, etc) testing. If this is a MR/PR, then the pipeline ends. If it is the push to the default branch (ie my release branch), then release job & deploy jobs are enabled depending on if I either set it to manually be triggered or allow auto-delivery/deployment. The release job is using semantic-release to determine if a release is required and then the deployment jobs depend on the result of that job.
Python Semantic Release Configuration
[tool.semantic_release.branches.release] match = "^(main|master)$" prerelease = false [tool.semantic_release.branches.other] # Used for enabling build jobs during PRs where a pre-release version is created on any # branch name but not published (ie. internal use from workflow artifacts) match = ".*" prerelease_token = "dev" prerelease = true [tool.semantic_release.remote] type = "gitlab" ignore_token_for_push = true token = { 'env': "GITLAB_TOKEN" }
GitLab Workflow
workflow: rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_PIPELINE_SOURCE =~ "/api|web|schedule|web|trigger|pipeline/"' - when: never stages: - .pre - check - test - release - deploy commit-lint: stage: check build: stage: check needs: - job: commit-lint script: - if git rev-parse --is-shallow-repository | grep -q "true"; then git fetch --unshallow --prune-tags --prune --all --force; fi - git checkout -B "$CI_COMMIT_BRANCH" HEAD - semantic-release version --no-commit --no-tag artifacts: paths: - dist/*.whl - dist/*.tar.gz expire_in: 1 week test: stage: test release: stage: release rules: - if: '$CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH' when: manual # <--- leave this out if you want auto-deployment allow_failure: false # must have when it is set to manual otherwise GitLab will move on to deploy environment: name: repository # custom environment that holds the PAT (and only available to this job) script: - if git rev-parse --is-shallow-repository | grep -q "true"; then git fetch --unshallow --prune-tags --prune --all --force; fi - git checkout -B "$CI_COMMIT_BRANCH" HEAD # set the remote url to the PAT (write repository access) - git remote set-url origin "https://__token__:$GITLAB_TOKEN@${CI_REPOSITORY_URL#*@}" # This provides an exit code of whether or not to release, on exitcode 0 it runs the release, # on non-zero it writes a status to a file that is passed on to the next job as an environment variable - if semantic-release -vv --strict version --print; then semantic-release version --skip-build; else printf '%s\n' "PSR_RELEASED=false" >> deploy.env; fi artifacts: reports: dotenv: deploy.env deploy-gl-pypi: stage: deploy needs: - job: release artifacts: true - job: build artifacts: true rules: - if: '$CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH' variables: TWINE_USERNAME: gitlab-ci-token TWINE_PASSWORD: $CI_JOB_TOKEN script: - if [ "PSR_RELEASED" = "true" ]; then twine upload --repository-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi" dist/*; fi
This pipeline handles the different version situations without the pipeline jobs failing (on a no release) because technically they did work as intended and there is no need for human intervention or review. OR you can just have the deploy fail when the version has not been bumped. It's a matter of preference.
One additional nuance that I do is actually run semantic-release in the build job but in a non-persistent way because I can gain the nicety to only have to have 1 place where the build command is defined. Secondly when building the artifact (versions stamped and everything) at the beginning of the pipeline I can now actually test the exact (hashed) item that is going to be released. Generally, using semantic-release to build at the end actually builds a new artifact (hashes are different) that wasn't tested--many people wave this risk. Since I have previously built and tested the built distribution, I just import the artifact from the build job during deployment while the release job skips the
build_commandwith--skip-build9 remaining items
@daniel-albuschat, I haven't gotten around to that but I did have it as an action item one of these days.
There is a way to check if the repo is already unshallowed and should be inluded as a bash conditional before the execution but I can't remember what it is at the moment. Will check later.
Reacted by Daniel AlbuschatI use a bash conditional around the
--unshallowcommand because of the failure that @daniel-albuschat mentioned above. Happens with small repositories under 50 commits (50 is the default fetch depth for GitLab) or if someone has already increased the fetch depth elsewhere.if git rev-parse --is-shallow-repository | grep -q "true"; then git fetch --unshallow --prune-tags --prune --all --force fi
@clarkecheckr, I recommend updating your workflow to handle this situation that I didn't include in my above example. (I did update the example above)
This issue has not received a response in 14 days. If no response is received in 7 days, it will be closed. We look forward to hearing from you.
This issue was closed because no response was received.
Sorry about commenting on a closed issue. There are mechanisms in GitLab to clone the whole repository instead of doing a shallow clone. You can do
release: stage: release variables: GIT_STRATEGY: clone GIT_DEPTH: "0" ...
instead of
release: stage: release script: - if git rev-parse --is-shallow-repository | grep -q "true"; then git fetch --unshallow --prune-tags --prune --all --force; fi ...
See:
@cfxegbert, it's a good thing to note for others. Do you know which version of GitLab that was introduced? I feel like it was pretty recent.
Also can you validate that it actually prunes or clones all the tags if the build directory is cached? That is a problem I had with GitLab was that deleted tags do not get cleaned up from a repo without
--prune-tags.The GIT_ variables have been available for several years. I've been using it for over 3 years. The
--prune-tagsmay be able to be set withGIT_FETCH_EXTRA_FLAGSbut I'm not sure if the flags are applied to clones or only fetch. Would you need--prune-tagon a clone?From the docs:
clone is the slowest option. It clones the repository from scratch for every job, ensuring that the local working copy is always pristine. If an existing worktree is found, it is removed before cloning.So it will not use the cached worktree like fetch does
Looking at the source
https://gitlab.com/gitlab-org/gitlab-runner/-/blob/main/shells/abstract.go#L535-540
https://gitlab.com/gitlab-org/gitlab-runner/-/blob/main/shells/abstract.go#L629-639to replicate your setup would be:
variables: GIT_STRATEGY: fetch GIT_DEPTH: "0" GIT_FETCH_EXTRA_FLAGS: --prune-tags --prune --all --force
With the
clonestrategy since it removes the directory I don't think you need to prune.The GIT_ variables have been available for several years. I've been using it for over 3 years.
I haven't tried to solve this problem in over 3 years so that's probably why it seems recent.
Would you need
--prune-tagon a clone?I doubt it because clone would fail if the directory exists.
And looks like you found another solution for my env, why thanks!
I haven't tried to solve this problem in over 3 years so that's probably why it seems recent.
FYI GIT_STRATEGY and GIT_DEPTH were added in v1.3.0 (2016). GIT_FETCH_EXTRA_FLAGS was added in v13.1 (2021).
Well there's a million ways to solve everything and I chose git rather than finding it in GitLab Docs.
Thank you all for your insights.
This issue thread along with the comments in #666 allowed me to setup my Gitlab pipeline in a short-ish amount of time.
The perfect addition for others now would be to add all this very helpful information as an official page in the docs automatic-releases.
That is the premise of #666.




Question
I need some help troubleshooting an issue I'm having. Versioning is working great up until the point where psr tries to create the version tag.
The failure just says
ERROR: Job failed: exit code 1with no other clue as to what's wrong.How do I further troubleshoot this?
Configuration
Semantic Release Configuration