Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 77 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,53 @@ name: CI
on:
push:
branches: [main]
tags: ['v*'] # path filters do not apply to tag pushes: releases always build
paths-ignore: ['**.md', 'LICENSE']
pull_request:
paths-ignore: ['**.md', 'LICENSE']

permissions:
contents: read

# A new push to a pull request cancels its previous run; main and tags always
# run to the end, since they publish the image.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15
env:
WOFF2_TAG: v1.0.2
WOFF2_SHA: 1bccf208bca986e53a647dfe4811322adb06ecf8
strategy:
matrix:
go: ['1.26.4', 'stable'] # exercise the go.mod minimum and the latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: ${{ matrix.go }}
- name: Install C dependencies
env:
WOFF2_TAG: v1.0.2
WOFF2_SHA: 1bccf208bca986e53a647dfe4811322adb06ecf8
run: |
sudo apt-get update
sudo apt-get install -y libharfbuzz-dev libbrotli-dev pkg-config g++
# The woff2 encoder is built from a pinned source, so its build is cached;
# the key also follows the runner image and compiler.
- id: toolchain
run: echo "key=$ImageOS-$(g++ -dumpfullversion)" >> "$GITHUB_OUTPUT"
- id: woff2-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/woff2-build
key: woff2-${{ env.WOFF2_SHA }}-O2-cstdint-${{ steps.toolchain.outputs.key }}
- name: Build the woff2 encoder
if: steps.woff2-cache.outputs.cache-hit != 'true'
run: |
# Ubuntu has no woff2 -dev package; build the encoder from a pinned source.
git clone --depth 1 --branch "$WOFF2_TAG" https://github.com/google/woff2 /tmp/woff2
test "$(git -C /tmp/woff2 rev-parse HEAD)" = "$WOFF2_SHA"
Expand All @@ -31,10 +58,53 @@ jobs:
src/woff2_enc.cc src/font.cc src/glyph.cc src/normalize.cc \
src/transform.cc src/table_tags.cc src/variable_length.cc \
src/woff2_common.cc src/woff2_out.cc
sudo ar rcs /usr/lib/libwoff2enc.a *.o
sudo cp -r include/woff2 /usr/include/
mkdir -p ~/woff2-build/include
ar rcs ~/woff2-build/libwoff2enc.a ./*.o
cp -r include/woff2 ~/woff2-build/include/
- name: Install the woff2 encoder
run: |
sudo cp ~/woff2-build/libwoff2enc.a /usr/lib/
sudo cp -r ~/woff2-build/include/woff2 /usr/include/
printf 'Name: woff2enc\nDescription: woff2 encoder\nVersion: 1.0.2\nLibs: -lwoff2enc -lbrotlienc -lbrotlicommon\nCflags:\n' \
| sudo tee /usr/lib/pkgconfig/libwoff2enc.pc > /dev/null
- run: go vet ./...
- run: go test ./...
- run: go build -o woffify .

# Publish only what passed the tests. Pull requests build the image without
# pushing it, so a broken Dockerfile shows up before the merge.
image:
needs: test
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
packages: write # push to ghcr.io
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- if: github.event_name == 'push'
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/gheop/woffify
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=tag
- uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
# Only main and tags refresh the layer cache; exporting it from every
# pull request run doubles the build step.
cache-to: ${{ github.event_name == 'push' && 'type=gha,mode=max' || '' }}
36 changes: 0 additions & 36 deletions .github/workflows/docker.yml

This file was deleted.

14 changes: 12 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ build-image:
- docker:27-dind
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG =~ /^v/'
variables:
IMAGE_TAG: latest
script:
- if [ -n "$CI_COMMIT_TAG" ]; then IMAGE_TAG="$CI_COMMIT_TAG"; fi
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
- docker build -t "$CI_REGISTRY_IMAGE:latest" .
- docker push "$CI_REGISTRY_IMAGE:latest"
# Layer cache kept in the registry: HarfBuzz is only rebuilt when the
# Dockerfile changes, not on every push.
- docker buildx create --use --driver docker-container
- >
docker buildx build --push
--cache-from "type=registry,ref=$CI_REGISTRY_IMAGE:buildcache"
--cache-to "type=registry,ref=$CI_REGISTRY_IMAGE:buildcache,mode=max,image-manifest=true,oci-mediatypes=true"
-t "$CI_REGISTRY_IMAGE:$IMAGE_TAG" .
30 changes: 26 additions & 4 deletions convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/binary"
"os"
"reflect"
"sync"
"testing"
)

Expand Down Expand Up @@ -83,10 +84,31 @@ func TestEncodeDeterministic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
for i := 0; i < 8; i++ {
next, err := encodeWOFF2(sfnt)
if err != nil {
t.Fatal(err)
// A different font to dirty the C heap between encodes. The v0.2.2 bug
// (uninitialized encode buffer) only showed up in batches: re-encoding the
// same font reuses a buffer holding the same bytes, which hides it.
other, err := subsetSFNT(sfnt, subsetOptions{unicodes: []unicodeRange{{0x20, 0x7E}}})
if err != nil {
t.Fatal(err)
}
// Concurrent encodes, like a batch run, each after encoding the other font.
outs := make([][]byte, 8)
errs := make([]error, len(outs))
var wg sync.WaitGroup
for i := range outs {
wg.Add(1)
go func() {
defer wg.Done()
if _, errs[i] = encodeWOFF2(other); errs[i] != nil {
return
}
outs[i], errs[i] = encodeWOFF2(sfnt)
}()
}
wg.Wait()
for i, next := range outs {
if errs[i] != nil {
t.Fatal(errs[i])
}
if !bytes.Equal(first, next) {
t.Fatalf("encodeWOFF2 is not deterministic (run %d differs)", i)
Expand Down
Loading