So the following slightly modified gitlab-ci.yml from the above very helpful example file generates a slightly different error when attempting to use postcss:
variables:
HUGO_ENV: production
THEME_URL: "github.com/google/docsy@v0.7.1"
CI_DEBUG_TRACE: "true"
DART_SASS_VERSION: 1.63.6
HUGO_VERSION: 0.115.3
NODE_VERSION: 20.x
GIT_DEPTH: 0
GIT_STRATEGY: clone
GIT_SUBMODULE_STRATEGY: recursive
TZ: Europe/Vienna
CI_DEBUG_TRACE: "true"
image:
name: golang:1.20.6-bookworm
pages:
script:
# Install brotli
- apt-get update
- apt-get install -y brotli
# Install Dart Sass
- curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
- tar -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
- cp -r dart-sass/* /usr/local/bin
- rm -rf dart-sass*
# Install Hugo
- curl -LJO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb
- apt-get install -y ./hugo_extended_${HUGO_VERSION}_linux-amd64.deb
- rm hugo_extended_${HUGO_VERSION}_linux-amd64.deb
# Install Node.js
- curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION} | bash -
- pwd
- apt-get install -y nodejs
# Install Node.js dependencies
- "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- ls -alF ./node_modules/
# Build
- hugo mod get $THEME_URL
- hugo --gc --minify
# Compress
- find public -type f -regex '.*\.\(css\|html\|js\|txt\|xml\)$' -exec gzip -f -k {} \;
- find public -type f -regex '.*\.\(css\|html\|js\|txt\|xml\)$' -exec brotli -f -k {} \;
artifacts:
paths:
- public
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
And the pipeline output ends with:
++ echo '$ apt-get update'
++ apt-get update
$ apt-get update
Get:1 http://deb.debian.org/debian bookworm InRelease [147 kB]
Get:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8904 kB]
Get:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [4732 B]
Get:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [48.0 kB]
Fetched 9204 kB in 3s (3429 kB/s)
Reading package lists...
++ echo '$ apt-get install -y brotli'
$ apt-get install -y brotli
++ apt-get install -y brotli
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
brotli
0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
Need to get 277 kB of archives.
After this operation, 788 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bookworm/main amd64 brotli amd64 1.0.9-2+b6 [277 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 277 kB in 0s (1109 kB/s)
Selecting previously unselected package brotli.
(Reading database ... 15610 files and directories currently installed.)
Preparing to unpack .../brotli_1.0.9-2+b6_amd64.deb ...
Unpacking brotli (1.0.9-2+b6) ...
Setting up brotli (1.0.9-2+b6) ...
++ echo '$ curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz'
$ curl -LJO https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
++ curl -LJO https://github.com/sass/dart-sass/releases/download/1.63.6/dart-sass-1.63.6-linux-x64.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 3665k 100 3665k 0 0 8681k 0 --:--:-- --:--:-- --:--:-- 8681k
++ echo '$ tar -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz'
$ tar -xf dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz
++ tar -xf dart-sass-1.63.6-linux-x64.tar.gz
++ echo '$ cp -r dart-sass/* /usr/local/bin'
$ cp -r dart-sass/* /usr/local/bin
++ cp -r dart-sass/sass dart-sass/src /usr/local/bin
++ echo '$ rm -rf dart-sass*'
$ rm -rf dart-sass*
++ rm -rf dart-sass dart-sass-1.63.6-linux-x64.tar.gz
++ echo '$ curl -LJO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb'
$ curl -LJO https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb
++ curl -LJO https://github.com/gohugoio/hugo/releases/download/v0.115.3/hugo_extended_0.115.3_linux-amd64.deb
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 19.0M 100 19.0M 0 0 18.9M 0 0:00:01 0:00:01 --:--:-- 33.0M
++ echo '$ apt-get install -y ./hugo_extended_${HUGO_VERSION}_linux-amd64.deb'
$ apt-get install -y ./hugo_extended_${HUGO_VERSION}_linux-amd64.deb
++ apt-get install -y ./hugo_extended_0.115.3_linux-amd64.deb
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
hugo
0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
Need to get 0 B/20.0 MB of archives.
After this operation, 59.1 MB of additional disk space will be used.
Get:1 /builds/pages/docs/hugo_extended_0.115.3_linux-amd64.deb hugo amd64 0.115.3 [20.0 MB]
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package hugo.
(Reading database ... 15616 files and directories currently installed.)
Preparing to unpack .../hugo_extended_0.115.3_linux-amd64.deb ...
Unpacking hugo (0.115.3) ...
Setting up hugo (0.115.3) ...
++ echo '$ rm hugo_extended_${HUGO_VERSION}_linux-amd64.deb'
$ rm hugo_extended_${HUGO_VERSION}_linux-amd64.deb
++ rm hugo_extended_0.115.3_linux-amd64.deb
++ echo '$ curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION} | bash -'
$ curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION} | bash -
++ bash -
++ curl -fsSL https://deb.nodesource.com/setup_20.x
## Installing the NodeSource Node.js 20.x repo...
## Populating apt-get cache...
+ apt-get update
Hit:1 http://deb.debian.org/debian bookworm InRelease
Hit:2 http://deb.debian.org/debian bookworm-updates InRelease
Hit:3 http://deb.debian.org/debian-security bookworm-security InRelease
Reading package lists...
## Installing packages required for setup: lsb-release...
+ apt-get install -y lsb-release > /dev/null 2>&1
## Confirming "bookworm" is supported...
+ curl -sLf -o /dev/null 'https://deb.nodesource.com/node_20.x/dists/bookworm/Release'
## Adding the NodeSource signing key to your keyring...
+ curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor | tee /usr/share/keyrings/nodesource.gpg >/dev/null
## Creating apt sources list file for the NodeSource Node.js 20.x repo...
+ echo 'deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x bookworm main' > /etc/apt/sources.list.d/nodesource.list
+ echo 'deb-src [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x bookworm main' >> /etc/apt/sources.list.d/nodesource.list
## Running `apt-get update` for you...
+ apt-get update
Hit:1 http://deb.debian.org/debian bookworm InRelease
Hit:2 http://deb.debian.org/debian bookworm-updates InRelease
Get:3 https://deb.nodesource.com/node_20.x bookworm InRelease [4586 B]
Hit:4 http://deb.debian.org/debian-security bookworm-security InRelease
Get:5 https://deb.nodesource.com/node_20.x bookworm/main amd64 Packages [776 B]
Fetched 5362 B in 0s (22.5 kB/s)
Reading package lists...
## Run `sudo apt-get install -y nodejs` to install Node.js 20.x and npm
## You may also need development tools to build native addons:
sudo apt-get install gcc g++ make
## To install the Yarn package manager, run:
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
++ echo '$ pwd'
$ pwd
++ pwd
/builds/pages/docs
++ echo '$ apt-get install -y nodejs'
$ apt-get install -y nodejs
++ apt-get install -y nodejs
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
nodejs
0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded.
Need to get 30.3 MB of archives.
After this operation, 194 MB of additional disk space will be used.
Get:1 https://deb.nodesource.com/node_20.x bookworm/main amd64 nodejs amd64 20.4.0-deb-1nodesource1 [30.3 MB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 30.3 MB in 1s (31.2 MB/s)
Selecting previously unselected package nodejs.
(Reading database ... 15624 files and directories currently installed.)
Preparing to unpack .../nodejs_20.4.0-deb-1nodesource1_amd64.deb ...
Unpacking nodejs (20.4.0-deb-1nodesource1) ...
Setting up nodejs (20.4.0-deb-1nodesource1) ...
++ echo '$ [[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true'
$ [[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true
++ [[ -f package-lock.json ]]
++ [[ -f npm-shrinkwrap.json ]]
++ true
++ echo '$ ls -alF ./node_modules/'
$ ls -alF ./node_modules/
++ ls -alF ./node_modules/
total 528
drwxrwxrwx 107 root root 4096 Jul 19 12:08 ./
drwxrwxrwx 14 root root 4096 Jul 19 12:08 ../
drwxrwxrwx 2 root root 4096 Jul 19 12:08 .bin/
-rw-rw-rw- 1 root root 84865 Jul 19 12:08 .package-lock.json
drwxrwxrwx 5 root root 4096 Jul 19 12:08 @nodelib/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 ansi-regex/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 ansi-styles/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 anymatch/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 argparse/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 array-union/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 at-least-node/
drwxrwxrwx 6 root root 4096 Jul 19 12:08 autoprefixer/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 binary-extensions/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 braces/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 browserslist/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 caller-callsite/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 caller-path/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 callsites/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 camelcase/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 caniuse-lite/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 chalk/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 chokidar/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 cliui/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 color-convert/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 color-name/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 colorette/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 cosmiconfig/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 decamelize/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 dependency-graph/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 dir-glob/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 electron-to-chromium/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 emoji-regex/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 error-ex/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 escalade/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 escape-string-regexp/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 esprima/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 fast-glob/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 fastq/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 fill-range/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 find-up/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 fs-extra/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 get-caller-file/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 get-stdin/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 glob-parent/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 globby/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 graceful-fs/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 has-flag/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 ignore/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 import-cwd/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 import-fresh/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 import-from/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-arrayish/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-binary-path/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-directory/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-extglob/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-fullwidth-code-point/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-glob/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 is-number/
drwxrwxrwx 5 root root 4096 Jul 19 12:08 js-yaml/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 json-parse-better-errors/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 jsonfile/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 locate-path/
drwxrwxrwx 3 root root 20480 Jul 19 12:08 lodash/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 log-symbols/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 merge2/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 micromatch/
drwxrwxrwx 6 root root 4096 Jul 19 12:08 nanoid/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 node-releases/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 normalize-path/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 normalize-range/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 num2fraction/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 p-limit/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 p-locate/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 p-try/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 parse-json/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 path-exists/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 path-type/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 picocolors/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 picomatch/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 pify/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 postcss/
drwxrwxrwx 5 root root 4096 Jul 19 12:08 postcss-cli/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 postcss-load-config/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 postcss-reporter/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 postcss-value-parser/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 pretty-hrtime/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 read-cache/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 readdirp/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 require-directory/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 require-main-filename/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 resolve-from/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 reusify/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 run-parallel/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 set-blocking/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 slash/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 source-map/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 source-map-js/
drwxrwxrwx 6 root root 4096 Jul 19 12:08 sprintf-js/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 string-width/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 strip-ansi/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 to-regex-range/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 universalify/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 update-browserslist-db/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 which-module/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 wrap-ansi/
drwxrwxrwx 2 root root 4096 Jul 19 12:08 y18n/
drwxrwxrwx 4 root root 4096 Jul 19 12:08 yargs/
drwxrwxrwx 3 root root 4096 Jul 19 12:08 yargs-parser/
++ echo '$ hugo mod get $THEME_URL'
$ hugo mod get $THEME_URL
++ hugo mod get github.com/google/docsy@v0.7.1
hugo: downloading modules …
hugo: collected modules in 22066 ms
++ echo '$ hugo --gc --minify'
$ hugo --gc --minify
++ hugo --gc --minify
Start building sites …
hugo v0.115.3-5c2e014a5150553a9fa4f9c1eb7dc4db89c0f1ab+extended linux/amd64 BuildDate=2023-07-13T16:11:34Z VendorInfo=gohugoio
WARN .File.UniqueID on zero object. Wrap it in if or with: {{ with .File }}{{ .UniqueID }}{{ end }}
Total in 4334 ms
Error: error building site: POSTCSS: failed to transform "scss/main.css" (text/css): sh: 1: postcss: Permission denied
Cleaning up project directory and file based variables
00:00
+ grep pipefail
+ set -o
+ set -o pipefail
+ set -o errexit
+ set +o noclobber
+ eval '$'\''rm'\'' -f /builds/pages/docs.tmp/CI_SERVER_TLS_CA_FILE
'
++ rm -f /builds/pages/docs.tmp/CI_SERVER_TLS_CA_FILE
+ :
+ exit 0
ERROR: Job failed: exit code 1
So if you take the error message:
Error: error building site: POSTCSS: failed to transform "scss/main.css" (text/css): sh: 1: postcss: Permission denied
at face value, the root user cannot transform some scss/main.css since it does not have the execute permission set. Which is a hard to swallow fact since the same permissions on the local build work great no problem incidentally the user on the local build is vscode:vscode in a devcontainer and here we are in a docker container as root:root.
Long story short, the pipeline definitely executes as the root user and the root user definitely could potentially use postcss but whatever happens inside the hugo black box appears to either trigger a spurious error message or the build isn’t executing things as the root user when it tries to access postcss.
So to summarize:
- I can use known working gitlab-ci.yml files from working sites and generate astonishingly similar failures on the gitlab system I am using.
- All the errors revolve around postcss and occur using the most current versions of hugo and postcss.
- The error is either "missing ./vendor directory", “no permission”, or “this feature is not available in your current Hugo version”
Checking now to see the permissions on /scss/main.css…
assuming the error message is referring to /public/scss/ seems obvious except there is no main.css in that directory. Perhaps /themes/docsy/assets/scss
At any rate, the /themes/docsy/assets/scss/main.css file shouldn’t need rwx for root to build the hugo site. Perhaps trying each version of docsy moving backwards until the error disappears to the next thing…