You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 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_BRANCH fails with the error fatal: '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_BRANCH is "", so the command reads git checkout -B HEAD and 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_BRANCH is 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.
I was able to get this working with the following config. The reason it was failing when using git checkout -B $CI_COMMIT_BRANCH HEAD was because when we get to the tag creation step the value of $CI_COMMIT_BRANCH is null. The following config checks to see if it's null, if it is then we set the variable to $CI_COMMIT_REF_NAME otherwise 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:rules to 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 using semantic-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 = truetoken = { '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: neverstages:
- .pre
- check
- test
- release
- deploycommit-lint:
stage: checkbuild:
stage: checkneeds:
- job: commit-lintscript:
- if git rev-parse --is-shallow-repository | grep -q "true"; thengit 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.gzexpire_in: 1 weektest:
stage: testrelease:
stage: releaserules:
- if: '$CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH'when: manual # <--- leave this out if you want auto-deploymentallow_failure: false # must have when it is set to manual otherwise GitLab will move on to deployenvironment:
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"; thengit 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; thensemantic-release version --skip-build;elseprintf '%s\n' "PSR_RELEASED=false" >> deploy.env;fiartifacts:
reports:
dotenv: deploy.envdeploy-gl-pypi:
stage: deployneeds:
- job: releaseartifacts: true
- job: buildartifacts: truerules:
- if: '$CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH'variables:
TWINE_USERNAME: gitlab-ci-tokenTWINE_PASSWORD: $CI_JOB_TOKENscript:
- if [ "PSR_RELEASED" = "true" ]; thentwine 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_command with --skip-build
@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.
I use a bash conditional around the --unshallow command 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)
@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-tags may be able to be set with GIT_FETCH_EXTRA_FLAGS but I'm not sure if the flags are applied to clones or only fetch. Would you need --prune-tag on 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
Activity
codejedi365 commentedon 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:
clarkecheckr commentedon Oct 1, 2024
Thanks for the prompt response. I didn't think the detached head state was the issue as I get a similar message in my branch yet there's no error.
I'll try these changes and report back.
clarkecheckr commentedon Oct 1, 2024
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?
codejedi365 commentedon Oct 1, 2024
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
clarkecheckr commentedon Oct 1, 2024
It's not a detached head, it's just the same message that the branch isn't in any release groups.
codejedi365 commentedon Oct 1, 2024
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.codejedi365 commentedon Oct 1, 2024
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.
clarkecheckr commentedon Oct 1, 2024
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.clarkecheckr commentedon Oct 1, 2024
Also, it only fails for the tag build.
clarkecheckr commentedon Oct 1, 2024
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.clarkecheckr commentedon Oct 1, 2024
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.clarkecheckr commentedon Oct 1, 2024
I 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?codejedi365 commentedon Oct 2, 2024
@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
GitLab Workflow
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
codejedi365 commentedon Oct 7, 2024
@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.
codejedi365 commentedon Oct 8, 2024
I 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.@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)
github-actions commentedon Oct 23, 2024
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.
github-actions commentedon Oct 31, 2024
This issue was closed because no response was received.
cfxegbert commentedon Jan 3, 2025
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
instead of
See:
codejedi365 commentedon Jan 3, 2025
@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.cfxegbert commentedon Jan 3, 2025
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
cfxegbert commentedon Jan 3, 2025
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-639
to replicate your setup would be:
With the
clonestrategy since it removes the directory I don't think you need to prune.codejedi365 commentedon Jan 3, 2025
I haven't tried to solve this problem in over 3 years so that's probably why it seems recent.
I doubt it because clone would fail if the directory exists.
And looks like you found another solution for my env, why thanks!
cfxegbert commentedon Jan 3, 2025
FYI GIT_STRATEGY and GIT_DEPTH were added in v1.3.0 (2016). GIT_FETCH_EXTRA_FLAGS was added in v13.1 (2021).
codejedi365 commentedon Jan 3, 2025
Well there's a million ways to solve everything and I chose git rather than finding it in GitLab Docs.
hhaidrr commentedon Mar 6, 2025
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.
codejedi365 commentedon Mar 6, 2025
That is the premise of #666.