Issues with build.ignore command not ignoring as required

I’ve been having a bunch of difficulties trying to get builds to only run when a certain subset of folders have changed. I thought I finally got things in a working condition but today I’m seeing a build that should be running is actually canceling early.

I’m working with a monorepo so in order to reduce our build times I’ve created an ignore script to only check for the particular folders that we care about. I’ve got a dummy directory for Netlify (.netlify-dummy-dir) that we target as the build directory.

We specify an ignore script (netlify-ignore.sh) file looks like this:

#!/bin/bash

cd ..

git diff --quiet HEAD^ HEAD \
  .netlify-dummy-dir/* \
  .storybook/* \
  app/javascript/* \
  babel.config.json \
  config/webpack/* \
  netlify.toml \
  tsconfig.json \
  yarn.lock \

(Separate note: we found that we were unable to do cd .. && git diff --quiet as a single command in our TOML file and that’s why we created a separate bash script to run)

Here is a build log that should be building but is instead canceling early:

1:26:25 PM: Build ready to start
1:26:27 PM: build-image version: b0258b965567defc4a2d7e2f2dec2e00c8f73ad6
1:26:27 PM: build-image tag: v3.4.1
1:26:27 PM: buildbot version: 648208d76731cd5bca75c1e9bc99d2032a1f1473
1:26:27 PM: Fetching cached dependencies
1:26:27 PM: Starting to download cache of 609.3MB
1:26:31 PM: Finished downloading cache in 4.203288656s
1:26:31 PM: Starting to extract cache
1:26:43 PM: Finished extracting cache in 12.030958208s
1:26:43 PM: Finished fetching cache in 16.589045472s
1:26:43 PM: Starting to prepare the repo for build
1:26:44 PM: Preparing Git Reference pull/17694/head
1:26:52 PM: Different build dir detected, going to use the one specified in the Netlify configuration file: '.netlify-dummy-dir' versus '' in the Netlify UI
1:26:52 PM: Different publish path detected, going to use the one specified in the Netlify configuration file: '.netlify-dummy-dir/.storybook-build' versus '' in the Netlify UI
1:26:52 PM: Different build command detected, going to use the one specified in the Netlify configuration file: 'cd .. ; yarn ; yarn storybook:build --quiet' versus '' in the Netlify UI
1:26:52 PM: Detected ignore command in Netlify configuration file. Proceeding with the specified command: 'sh ../netlify-ignore.sh'
1:26:52 PM: User-specified ignore command returned exit code 0. Returning early from build.
1:26:52 PM: Failed during stage 'checking build content for changes': Canceled build due to no content change
1:26:52 PM: Finished processing build request in 25.536267909s

There are changes on this branch in the app/javascript/* folder that should mean we get a non-zero exit code from the git diff --quiet command. When I run the command locally (running git diff master HEAD) I can see the changes are there.

Is there any extra step that I’m missing? Is there an easy way to debug this? Due to company confidentiality I cannot provide the site name but perhaps this redacted build URL can help: https://app.netlify.com/sites/[redacted]/deploys/5f7246f138502f00086f0722

Any help would be greatly appreciated!

Hi, @gray. Note, the deploy you linked to (our support team can find it using the deploy ID alone), isn’t for the master branch.

That might explain part of the issue. (I say this because you mentioned “git diff master HEAD”.)

You also asked about an easy way to debug this. Actually, there isn’t because there is no logging done by the build.ignore command. It might help to confirm that the cd .. is needed by checking for it with something like this:

if [ -d ".netlify-dummy-dir" ] 
then
    exit 1 # the build continues
else
    exit # the build ends
fi

This would be for testing only of course. I’m suggesting this because I’m concerned that the build.ignore ignores the build.base setting. This check above is to confirm which directory you are in only.

There is no logging so the exist codes are the only way to test.

If this doesn’t help or if there are other questions, please let us know.

Thanks Luke! Is there a way to run the equivalent of git diff HEAD^ HEAD locally? I can’t quite figure out what Netlify is referring to as HEAD^.

I’ll double check the build directory theory, though!

I can confirm that it’s in the correct folder. I update the ignore script to:

pwd

if [ -d ".netlify-dummy-dir" ] 
then
    exit 1 # the build continues
else
    exit # the build ends
fi

And the relevant section from the build:

9:31:09 AM: Detected ignore command in Netlify configuration file. Proceeding with the specified command: 'sh ../netlify-ignore.sh'
9:31:09 AM: /opt/build/repo/.netlify-dummy-dir
9:31:09 AM: Starting build script

So that’s good! So if it has nothing to do with the directory then it has something to do with what I’m comparing in a git diff.

Alrighty! So I’m pretty sure the problem is just based on how I’m doing git diff. Because the documentation shows to use HEAD^ HEAD I thought Netlify was doing something clever to only need to compare those two. But just like on my local machine, HEAD^ is only referencing the previous commit. This means that if my branch has multiple commits it’s only comparing between the last two – not ideal!

So maybe I’m missing something here: how do I reference the equivalent of master from Netlify? If I try to reference master it’s a commit from over a month ago. I’m guessing I’m just missing a tiny bit of git knowledge that would get me over the finish line!

Hi, @gray. I don’t have a good “one line” solution.

This might be done programmatically. For example, you can get the first commit in the branch like so:

first_branch_commit="$(git log master..HEAD --pretty=oneline | tail -n 1 | awk '{print $1}')"

Then that can be use to diff from that point to now:

git diff --quiet "${first_branch_commit}" HEAD \
  .netlify-dummy-dir/* \
  .storybook/* \
  app/javascript/* \
  babel.config.json \
  config/webpack/* \
  netlify.toml \
  tsconfig.json \
  yarn.lock \

Again, this will alway check from the first commit in the branch until now. If you are looking to check from the last build at Netlify, this information isn’t stored in the git repo so some other solution would be needed.

If there are other questions about this, please let us know.

Thanks, Luke! I’ll play around a little bit more. Unfortunately I don’t think comparing to master is going to help because that could potentially be super behind.

I guess I’m a little confused with the documentation, though? It seems like comparing HEAD^ HEAD would be useless unless your branches always only ever contained a single commit.

For now I’ve updated the script to be:

last_merge="$(git log --pretty=format:"%H" --merges -n 1)"
echo "Comparing most recent merge commit ($last_merge) with HEAD..."

git diff --quiet $last_merge HEAD \
  .netlify-dummy-dir/* \
  .storybook/* \
  app/javascript/* \
  babel.config.json \
  config/webpack/* \
  netlify.toml \
  tsconfig.json \
  yarn.lock

This doesn’t quite solve the problem because not all developers on the team use the merge button in Github that results in a merge commit but this gets us most of the way there.

In its current state this feature doesn’t provide as much value to us as we were hoping. If we can’t confidently run a git diff to check the changes that the particular pull request is introducing then we’re always going to get either false negatives or false positives depending on how we implement the diff.

I’d love to see this improved!

Hi, @gray. I do think the pieces exist for a high confidence solution but there is no pre-existing tooling to do so.

The workflow would require using our API manually at the moment and I agree it would be great if we had some prior art to demonstrate this.

The process I envision works something like this:

  • the script would first call our API to confirm the published deploy id for all branches with an API call to :

    https://api.netlify.com/api/v1/sites/{site-id}/deployed-branches
    
  • then the deploy id for this branch’s current deploy would be checked to get the Git commit reference SHA-1 value

    https://api.netlify.com/api/v1/deploys/{deploy-id}
    

This assumes that checking for changes between the commit for currently deployed branch and the commit being used for the build is the requirement.

I’ve tested the API and confirmed this can all be done.

If that would meet your requirement, I’d be happy to enter this as a feature request that there be a way to do that without writing the code yourself.

I’d also be happy to answer questions if you wanted to write custom code to query the API to do this in the meantime.

If you want me to enter this as a feature request, please confirm and I’ll do so. Likewise if there are any API question, please reply anytime.

EDIT: I also edited the title of this topic. I wanted to point it out for transparency and I hope you don’t mind. I’m trying to make the topic subject clear.

Thanks Luke! I’ll play around with that and see how it looks. Something else I’m considering is seeing if I can manually add a remote so that I can git fetch origin master. The ENV should have the appropriate credentials to be able to talk to Github but I’ll report back with my findings.

Regarding a proper feature request I think this would be something that most people would assume the platform is capable of due to the documentation referring to ignoring via Git but I’m a little surprised if I’m the first one to hit this issue!

(no worries about updating the title :slight_smile:)

I can tell you already, and sorry to be late with this info, but…

You won’t have ANY git permissions you don’t bring yourself; we drop all permissions BEFORE running any of your code.

You might find this article helpful in coming up with a workflow that works for you:

Hi, @gray. I cannot believe I missed this from the environment variable documentation about Git metadata:

  • COMMIT_REF : Reference ID (also known as ‘SHA’ or ‘hash’) of the commit we’re building.
  • CACHED_COMMIT_REF : Reference ID (also known as ‘SHA’ or ‘hash’) of the last commit that we built before the current build.

There is an environment variable of the previous build’s commit SHA-1 ref. With this environment variable, I don’t think any API calls are needed. Does this meet the requirements for the build.ignore command?

git diff --quiet "${CACHED_COMMIT_REF}" "${COMMIT_REF}" \
  .netlify-dummy-dir/* \
  .storybook/* \
  app/javascript/* \
  babel.config.json \
  config/webpack/* \
  netlify.toml \
  tsconfig.json \
  yarn.lock \

Oooooo nice one @luke! I’ll give that a try. I think for our first build it might be a little out of date since we’re in a weird place in our build right now but this might work once we get it merged! I’ll give it a go and report back.

I think this is going to work for us!

1 Like

I’ve added a todo item to write a support guide which covers this topic all in one place as well. :+1:

2 Likes

Did this end up working for you? I am trying to do something similar, and replicated what you tried in our repo, and nothing seems to be different, i.e. site is built on every change in the repo.

Hi, @ChrisChinchilla. Would you please send us a deploy id for a deploy which didn’t handle the build.ingore command as expected?

Our support team will be happy to take a look to see if we can find a solution.

Sure 5fc519553a1e4e00085592ac, it’s not that it doesn’t work, but I find the current docs hard to interpret to make it work. Basically, I only want to build on changes to the site folder.

hey chris, while luke works on that, can you tell me a little more about what is confusing? if we can, i’d like to make the docs more clear.

@perry I just posted a similar ticket related to this, can you help me out

https://answers.netlify.com/t/build-netlify-only-if-base-dir-changes/27694