├── .gitignore
├── scripts
├── .syncignore
├── options.json
├── .util
│ ├── tools.json
│ ├── print.sh
│ └── tools.sh
├── publish.sh
└── smoke.sh
├── smoke
├── testdata
│ ├── go
│ │ ├── .gitignore
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── README.md
│ │ └── main.go
│ ├── python
│ │ ├── .gitignore
│ │ ├── Procfile
│ │ ├── Pipfile
│ │ ├── templates
│ │ │ └── index.html
│ │ ├── README.md
│ │ ├── server.py
│ │ └── Pipfile.lock
│ ├── nodejs
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── package.json
│ │ └── server.js
│ ├── procfile
│ │ ├── config.yml
│ │ ├── web
│ │ │ └── hello-world.txt
│ │ ├── Procfile
│ │ └── static-file-server-1.8.0-linux-amd64
│ ├── ruby
│ │ ├── config.ru
│ │ ├── Gemfile
│ │ ├── app.rb
│ │ └── README.md
│ ├── java-native-image
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── resources
│ │ │ │ │ └── application.properties
│ │ │ │ └── java
│ │ │ │ │ └── io
│ │ │ │ │ └── paketo
│ │ │ │ │ └── demo
│ │ │ │ │ └── DemoApplication.java
│ │ │ └── test
│ │ │ │ └── java
│ │ │ │ └── io
│ │ │ │ └── paketo
│ │ │ │ └── demo
│ │ │ │ └── DemoApplicationTests.java
│ │ ├── .mvn
│ │ │ └── wrapper
│ │ │ │ ├── maven-wrapper.jar
│ │ │ │ ├── maven-wrapper.properties
│ │ │ │ └── MavenWrapperDownloader.java
│ │ ├── README.md
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ ├── mvnw.cmd
│ │ └── mvnw
│ ├── javascript-frontend
│ │ ├── public
│ │ │ ├── robots.txt
│ │ │ ├── favicon.ico
│ │ │ └── index.html
│ │ ├── src
│ │ │ ├── App.css
│ │ │ ├── index.js
│ │ │ └── App.js
│ │ ├── .gitignore
│ │ ├── README.md
│ │ └── package.json
│ ├── dotnet
│ │ ├── obj
│ │ │ ├── runtime.csproj.nuget.g.targets
│ │ │ ├── project.nuget.cache
│ │ │ ├── runtime.csproj.nuget.g.props
│ │ │ ├── project.assets.json
│ │ │ └── runtime.csproj.nuget.dgspec.json
│ │ ├── runtime.csproj
│ │ ├── README.md
│ │ └── Program.cs
│ ├── httpd
│ │ ├── htdocs
│ │ │ └── index.html
│ │ ├── README.md
│ │ └── httpd.conf
│ └── nginx
│ │ ├── public
│ │ └── index.html
│ │ ├── README.md
│ │ ├── nginx.conf
│ │ └── mime.types
├── init_test.go
├── dotnet_test.go
├── procfile_test.go
├── go_test.go
├── nodejs_test.go
├── ruby_test.go
├── python_test.go
├── java_test.go
├── java_native_image_test.go
└── web_servers_test.go
├── .github
├── .syncignore
├── CODEOWNERS
├── renovate.json
├── workflows
│ ├── synchronize-labels.yml
│ ├── lint-yaml.yml
│ ├── test-builder.yml
│ ├── update-github-config.yml
│ ├── approve-bot-pr.yml
│ ├── test-pull-request.yml
│ ├── update-go-mod-version.yml
│ ├── push-image.yml
│ ├── update-builder-toml.yml
│ ├── update-test-data.yml
│ └── create-release.yml
├── release-drafter-config.yml
└── labels.yml
├── README.md
├── go.mod
├── LICENSE
└── go.sum
/.gitignore:
--------------------------------------------------------------------------------
1 | .bin/
2 |
--------------------------------------------------------------------------------
/scripts/.syncignore:
--------------------------------------------------------------------------------
1 | options.json
--------------------------------------------------------------------------------
/smoke/testdata/go/.gitignore:
--------------------------------------------------------------------------------
1 | !vendor
2 |
--------------------------------------------------------------------------------
/smoke/testdata/python/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | venv
--------------------------------------------------------------------------------
/smoke/testdata/nodejs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/smoke/testdata/procfile/config.yml:
--------------------------------------------------------------------------------
1 | folder: web
2 |
--------------------------------------------------------------------------------
/smoke/testdata/procfile/web/hello-world.txt:
--------------------------------------------------------------------------------
1 | Hello World!
--------------------------------------------------------------------------------
/smoke/testdata/python/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn server:app
2 |
--------------------------------------------------------------------------------
/.github/.syncignore:
--------------------------------------------------------------------------------
1 | CODEOWNERS
2 | dependabot.yml
3 | renovate.json
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @paketo-buildpacks/builders-maintainers
2 |
--------------------------------------------------------------------------------
/scripts/options.json:
--------------------------------------------------------------------------------
1 | {
2 | "push_builder_to_local_registry": true
3 | }
4 |
--------------------------------------------------------------------------------
/smoke/testdata/ruby/config.ru:
--------------------------------------------------------------------------------
1 | require './app'
2 | run Sinatra::Application
3 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/scripts/.util/tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "crane": "v0.20.7",
3 | "pack": "v0.39.1"
4 | }
5 |
--------------------------------------------------------------------------------
/smoke/testdata/procfile/Procfile:
--------------------------------------------------------------------------------
1 | web: ./static-file-server-1.8.0-linux-amd64 --config config.yml
2 |
--------------------------------------------------------------------------------
/smoke/testdata/ruby/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | ruby '~> 3'
4 |
5 | gem 'puma'
6 | gem 'sinatra'
7 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/smoke/testdata/go/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/paketo-buildpacks/samples/go/mod
2 |
3 | go 1.15
4 |
5 | require github.com/gorilla/mux v1.8.0
6 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paketo-buildpacks/builder-jammy-base/HEAD/smoke/testdata/javascript-frontend/public/favicon.ico
--------------------------------------------------------------------------------
/smoke/testdata/procfile/static-file-server-1.8.0-linux-amd64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paketo-buildpacks/builder-jammy-base/HEAD/smoke/testdata/procfile/static-file-server-1.8.0-linux-amd64
--------------------------------------------------------------------------------
/smoke/testdata/go/go.sum:
--------------------------------------------------------------------------------
1 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
2 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
3 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paketo-buildpacks/builder-jammy-base/HEAD/smoke/testdata/java-native-image/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/obj/runtime.csproj.nuget.g.targets:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/smoke/testdata/python/Pipfile:
--------------------------------------------------------------------------------
1 | [packages]
2 | Flask = "==2.1.3"
3 | gunicorn = "*"
4 | itsdangerous = "==2.1.2"
5 |
6 | [dev-packages]
7 | tox = "*"
8 | coverage = "*"
9 | "flake8" = "*"
10 | flask-testing = "*"
11 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | font-size: large;
3 | text-align: center;
4 | }
5 |
6 | .App img {
7 | display: block;
8 | margin-left: auto;
9 | margin-right: auto;
10 | width: 50%;
11 | }
12 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(
6 |
7 |
8 | ,
9 | document.getElementById('root')
10 | );
11 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/obj/project.nuget.cache:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "dgSpecHash": "jpCLVXQFwpwtdWzwIcGgkt61LJcD8OAErgte8zO7IDiGI+L4I77KWipQuEmgt/th6mqVISAAKEyvHsFodpYTcg==",
4 | "success": true,
5 | "projectFilePath": "/tmp/runtime/runtime.csproj",
6 | "expectedPackageFiles": [],
7 | "logs": []
8 | }
--------------------------------------------------------------------------------
/smoke/testdata/nodejs/README.md:
--------------------------------------------------------------------------------
1 | # Node.js Sample App using NPM
2 |
3 | ## Building
4 |
5 | `pack build npm-sample --buildpack docker.io/paketobuildpacks/nodejs`
6 |
7 | ## Running
8 |
9 | `docker run --interactive --tty --publish 8080:8080 npm-sample`
10 |
11 | ## Viewing
12 |
13 | `curl http://localhost:8080`
14 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/runtime.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/smoke/testdata/go/README.md:
--------------------------------------------------------------------------------
1 | # Go Sample App using Mod
2 |
3 | ## Building
4 |
5 | `pack build mod-sample --buildpack docker.io/paketobuildpacks/go`
6 |
7 | ## Running
8 |
9 | `docker run --interactive --tty --env PORT=8080 --publish 8080:8080 mod-sample`
10 |
11 | ## Viewing
12 |
13 | `curl http://localhost:8080`
14 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 |
3 | function App() {
4 | return
5 |

6 | Powered by Paketo Buildpacks
7 |
;
8 | }
9 |
10 | export default App;
11 |
--------------------------------------------------------------------------------
/smoke/testdata/httpd/htdocs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powered By Paketo Buildpacks
5 |
6 |
7 |
8 |
9 | `
10 |
--------------------------------------------------------------------------------
/smoke/testdata/nginx/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powered By Paketo Buildpacks
5 |
6 |
7 |
8 |
9 | `
10 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/src/test/java/io/paketo/demo/DemoApplicationTests.java:
--------------------------------------------------------------------------------
1 | package io.paketo.demo;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class DemoApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/smoke/testdata/python/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Powered By Paketo Buildpacks
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/smoke/testdata/python/README.md:
--------------------------------------------------------------------------------
1 | # Python sample app using pipenv package manager
2 |
3 | ## Building
4 |
5 | `pack build pipenv-sample --buildpack docker.io/paketobuildpacks/python`
6 |
7 | ## Running
8 |
9 | `docker run --interactive --tty --env PORT=8080 --publish 8080:8080 pipenv-sample`
10 |
11 | ## Viewing
12 |
13 | `curl http://localhost:8080`
14 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/README.md:
--------------------------------------------------------------------------------
1 | # Dotnet Core Sample App using Runtime only
2 |
3 | ## Building
4 |
5 | `pack build dotnet-runtime-sample --buildpack docker.io/paketobuildpacks/dotnet-core`
6 |
7 | ## Running
8 |
9 | `docker run --interactive --tty --env PORT=8080 --publish 8080:8080 dotnet-runtime-sample`
10 |
11 | ## Viewing
12 |
13 | `curl http://localhost:8080`
14 |
--------------------------------------------------------------------------------
/smoke/testdata/nginx/README.md:
--------------------------------------------------------------------------------
1 | # NGINX Server Sample Application
2 |
3 | ## Building
4 |
5 | ```bash
6 | pack build my-nginx-app --buildpack docker.io/paketobuildpacks/nginx
7 | ```
8 |
9 | ## Running
10 |
11 | ```bash
12 | docker run --tty --env PORT=8080 --publish 8080:8080 my-nginx-app
13 | ```
14 |
15 | ## Viewing
16 |
17 | ```bash
18 | curl -s localhost:8080
19 | ```
20 |
--------------------------------------------------------------------------------
/smoke/testdata/httpd/README.md:
--------------------------------------------------------------------------------
1 | # HTTPD Server Sample Application
2 |
3 | ## Building
4 |
5 | ```bash
6 | pack build my-httpd-app --buildpack docker.io/paketobuildpacks/httpd --builder paketobuildpacks/builder:full
7 | ```
8 |
9 | ## Running
10 |
11 | ```bash
12 | docker run --tty --env PORT=8080 --publish 8080:8080 my-httpd-app
13 | ```
14 |
15 | ## Viewing
16 |
17 | ```bash
18 | curl -s localhost:8080
19 | ```
20 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/src/main/java/io/paketo/demo/DemoApplication.java:
--------------------------------------------------------------------------------
1 | package io.paketo.demo;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class DemoApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(DemoApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/smoke/testdata/ruby/app.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra'
2 | configure { set :server, :puma }
3 |
4 | get '/' do
5 | '
6 |
7 |
8 | Powered By Paketo Buildpacks
9 |
10 |
11 |
12 |
13 | '
14 | end
15 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/smoke/testdata/ruby/README.md:
--------------------------------------------------------------------------------
1 | # Ruby sample app using Puma web server
2 |
3 | ## Building
4 |
5 | `pack build puma-sample --buildpack paketo-buildpacks/ruby`
6 |
7 | ## Running
8 |
9 | `docker run --interactive --tty --publish 9292:9292 puma-sample`
10 |
11 | `9292` is the default port for rack compliant web servers. As of date, the puma
12 | buildpack requires that the app source have a `config.ru` file.
13 |
14 | ## Viewing
15 |
16 | `curl http://localhost:9292`
17 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/README.md:
--------------------------------------------------------------------------------
1 | # Java Native Image Sample Application
2 |
3 | ## Building
4 |
5 | ```bash
6 | pack build applications/native-image \
7 | --builder paketobuildpacks/builder-jammy-base \
8 | --env BP_NATIVE_IMAGE=true
9 | ```
10 |
11 | ## Running
12 |
13 | ```bash
14 | docker run --rm --tty --publish 8080:8080 applications/native-image
15 | ```
16 |
17 | ## Viewing
18 |
19 | ```bash
20 | curl -s http://localhost:8080/actuator/health | jq .
21 | ```
22 |
--------------------------------------------------------------------------------
/smoke/testdata/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Paketo Buildpacks",
3 | "dependencies": {
4 | "express": "^4.17.0"
5 | },
6 | "description": "Sample Node.js Application using NPM",
7 | "license": "Apache-2.0",
8 | "name": "sample",
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/paketo-buildpacks/samples"
12 | },
13 | "scripts": {
14 | "start": "echo \"start\" && node server.js"
15 | },
16 | "version": "0.0.0"
17 | }
18 |
--------------------------------------------------------------------------------
/.github/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "github>paketo-buildpacks/github-config//renovate/renovate-default"
5 | ],
6 | "enabledManagers": ["gomod"],
7 | "packageRules": [
8 | {
9 | "matchPaths": ["**/smoke/testdata/**"],
10 | "enabled": false,
11 | "description": "The test data are updated by syncing them with the samples."
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/.github/workflows/synchronize-labels.yml:
--------------------------------------------------------------------------------
1 | name: Synchronize Labels
2 | "on":
3 | push:
4 | branches:
5 | - main
6 | paths:
7 | - .github/labels.yml
8 | workflow_dispatch: {}
9 | jobs:
10 | synchronize:
11 | name: Synchronize Labels
12 | runs-on:
13 | - ubuntu-24.04
14 | steps:
15 | - uses: actions/checkout@v6
16 | - uses: micnncim/action-label-syncer@v1
17 | env:
18 | GITHUB_TOKEN: ${{ github.token }}
19 |
--------------------------------------------------------------------------------
/smoke/testdata/nodejs/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const port = process.env.PORT || 8080;
3 |
4 | const app = express();
5 |
6 | app.get('/', (request, response) => {
7 | response.send(`
8 |
9 |
10 | Powered By Paketo Buildpacks
11 |
12 |
13 |
14 |
15 | `);
16 | });
17 |
18 | app.listen(port);
19 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/smoke/testdata/python/server.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, render_template
2 | import subprocess
3 | import gunicorn
4 |
5 |
6 | app = Flask(__name__)
7 |
8 | @app.route("/")
9 | def hello():
10 | return render_template('index.html')
11 |
12 | @app.route('/execute', methods=['POST'])
13 | def execute():
14 | with open('runtime.py', 'w') as f:
15 | f.write(request.values.get('code'))
16 | return subprocess.check_output(["python", "runtime.py"])
17 |
18 | @app.route('/versions')
19 | def versions():
20 | version = gunicorn.__version__
21 | return "Gunicorn version: " + version
22 |
23 | app.debug=True
24 |
--------------------------------------------------------------------------------
/.github/release-drafter-config.yml:
--------------------------------------------------------------------------------
1 | # Config for https://github.com/release-drafter/release-drafter
2 | name-template: '$RESOLVED_VERSION'
3 | tag-template: 'v$RESOLVED_VERSION'
4 | filter-by-commitish: true
5 | commitish: main
6 |
7 | change-template: '- $TITLE [#$NUMBER] by [@$AUTHOR](https://github.com/$AUTHOR)'
8 | template: |
9 | ## Full Changelog
10 |
11 | Following pull requests got merged for this release:
12 |
13 | $CHANGES
14 |
15 | version-resolver:
16 | major:
17 | labels:
18 | - 'semver:major'
19 | minor:
20 | labels:
21 | - 'semver:minor'
22 | patch:
23 | labels:
24 | - 'semver:patch'
25 | default: patch
26 |
--------------------------------------------------------------------------------
/smoke/testdata/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 | daemon off;
3 |
4 | error_log stderr;
5 | events { worker_connections 1024; }
6 |
7 | http {
8 | charset utf-8;
9 | log_format cloudfoundry 'NginxLog "$request" $status $body_bytes_sent';
10 | access_log /dev/stdout cloudfoundry;
11 | default_type application/octet-stream;
12 | include mime.types;
13 | sendfile on;
14 |
15 | tcp_nopush on;
16 | keepalive_timeout 30;
17 | port_in_redirect off; # Ensure that redirects don't include the internal container PORT - 8080
18 |
19 | server {
20 | listen {{port}};
21 | root public;
22 | index index.html index.htm Default.htm;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/smoke/testdata/go/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/gorilla/mux"
10 | )
11 |
12 | const INDEX = `
13 |
14 |
15 | Powered By Paketo Buildpacks
16 |
17 |
18 |
19 |
20 | `
21 |
22 | func main() {
23 | router := mux.NewRouter()
24 | router.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
25 | fmt.Fprintln(w, INDEX)
26 | })
27 |
28 | log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), router))
29 | }
30 |
--------------------------------------------------------------------------------
/.github/workflows/lint-yaml.yml:
--------------------------------------------------------------------------------
1 | name: Lint Workflows
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '.github/**.yml'
7 | - '.github/**.yaml'
8 |
9 | jobs:
10 | lintYaml:
11 | runs-on: ubuntu-24.04
12 | steps:
13 | - uses: actions/checkout@v6
14 |
15 | - name: Checkout github-config
16 | uses: actions/checkout@v6
17 | with:
18 | repository: paketo-buildpacks/github-config
19 | path: github-config
20 |
21 | - name: Set up Python
22 | uses: actions/setup-python@v5
23 | with:
24 | python-version: 3.8
25 |
26 | - name: Install yamllint
27 | run: pip install yamllint
28 |
29 | - name: Lint YAML files
30 | run: yamllint ./.github -c github-config/.github/.yamllint
31 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Create React App
2 |
3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
4 |
5 | ## Available Scripts
6 |
7 | In the project directory, you can run:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.\
12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
13 |
14 | The page will reload when you make changes.\
15 | You may also see any lint errors in the console.
16 |
17 | ### `npm run build`
18 |
19 | Builds the app for production to the `build` folder.\
20 | It correctly bundles React in production mode and optimizes the build for the best performance.
21 |
22 | The build is minified and the filenames include the hashes.\
23 | Your app is ready to be deployed!
24 |
25 | See the section about
26 | [deployment](https://facebook.github.io/create-react-app/docs/deployment) for
27 | more information.
28 |
29 |
--------------------------------------------------------------------------------
/smoke/init_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "flag"
5 | "testing"
6 | "time"
7 |
8 | "github.com/onsi/gomega/format"
9 | "github.com/sclevine/spec"
10 | "github.com/sclevine/spec/report"
11 |
12 | . "github.com/onsi/gomega"
13 | )
14 |
15 | var Builder string
16 |
17 | func init() {
18 | flag.StringVar(&Builder, "name", "", "")
19 | }
20 |
21 | func TestSmoke(t *testing.T) {
22 | format.MaxLength = 0
23 | Expect := NewWithT(t).Expect
24 |
25 | flag.Parse()
26 |
27 | Expect(Builder).NotTo(Equal(""))
28 |
29 | SetDefaultEventuallyTimeout(60 * time.Second)
30 |
31 | suite := spec.New("Smoke", spec.Parallel(), spec.Report(report.Terminal{}))
32 | suite("Dotnet", testDotnet)
33 | suite("Go", testGo)
34 | suite("Java Native Image", testJavaNativeImage)
35 | suite("Java", testJava)
36 | suite("Node.js", testNodejs)
37 | suite("Procfile", testProcfile)
38 | suite("Python", testPython)
39 | suite("Ruby", testRuby)
40 | suite("Web Servers", testWebServers)
41 | suite.Run(t)
42 | }
43 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-nginx",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.4",
7 | "@testing-library/react": "^13.1.1",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^18.0.0",
10 | "react-dom": "^18.0.0",
11 | "react-scripts": "5.0.1",
12 | "web-vitals": "^2.1.4"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Paketo Jammy Base Builder
2 |
3 | ## `paketobuildpacks/builder-jammy-base`
4 |
5 | This builder uses the [Paketo Jammy Base
6 | Stack](https://github.com/paketo-buildpacks/jammy-base-stack) (Ubuntu Jammy
7 | Jellyfish build and run images) with buildpacks for Java,
8 | Java Native Image, Go, Python, .NET, Node.js, Apache HTTPD, NGINX and Procfile.
9 |
10 | To see which versions of build and run images, buildpacks, and the lifecycle
11 | that are contained within a given builder version, see the
12 | [Releases](https://github.com/paketo-buildpacks/builder-jammy-base/releases) on this
13 | repository. This information is also available in the `builder.toml`.
14 |
15 | For more information about this builder and how to use it, visit the [Paketo
16 | builder documentation](https://paketo.io/docs/builders/). To learn about the
17 | stack included in this builder, visit the [Paketo stack
18 | documentation](https://paketo.io/docs/stacks/) and the [Paketo Jammy Base Stack
19 | repo](https://github.com/paketo-buildpacks/jammy-base-stack).
20 |
--------------------------------------------------------------------------------
/scripts/.util/print.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | function util::print::title() {
7 | local blue reset message
8 | blue="\033[0;34m"
9 | reset="\033[0;39m"
10 | message="${1}"
11 |
12 | echo -e "\n${blue}${message}${reset}" >&2
13 | }
14 |
15 | function util::print::info() {
16 | local message
17 | message="${1}"
18 |
19 | echo -e "${message}" >&2
20 | }
21 |
22 | function util::print::error() {
23 | local message red reset
24 | message="${1}"
25 | red="\033[0;31m"
26 | reset="\033[0;39m"
27 |
28 | echo -e "${red}${message}${reset}" >&2
29 | exit 1
30 | }
31 |
32 | function util::print::success() {
33 | local message green reset
34 | message="${1}"
35 | green="\033[0;32m"
36 | reset="\033[0;39m"
37 |
38 | echo -e "${green}${message}${reset}" >&2
39 | exitcode="${2:-0}"
40 | exit "${exitcode}"
41 | }
42 |
43 | function util::print::warn() {
44 | local message yellow reset
45 | message="${1}"
46 | yellow="\033[0;33m"
47 | reset="\033[0;39m"
48 |
49 | echo -e "${yellow}${message}${reset}" >&2
50 | exit 0
51 | }
52 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/obj/runtime.csproj.nuget.g.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | True
5 | NuGet
6 | $(MSBuildThisFileDirectory)project.assets.json
7 | /home/ubuntu/.nuget/packages/
8 | /home/ubuntu/.nuget/packages/
9 | PackageReference
10 | 6.2.1
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/smoke/testdata/javascript-frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
21 | Paketo Buildpacks
22 |
23 |
24 |
25 |
26 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using System.Net;
7 | using System.Net.Sockets;
8 |
9 | namespace runtime
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | string port = Environment.GetEnvironmentVariable("PORT");
16 | TcpListener server = new TcpListener(IPAddress.Any, Int32.Parse(port));
17 |
18 | server.Start();
19 |
20 | while (true)
21 | {
22 | TcpClient client = server.AcceptTcpClient();
23 | NetworkStream ns = client.GetStream();
24 |
25 | string document = @"
26 |
27 |
28 | Powered By Paketo Buildpacks
29 |
30 |
31 |
32 |
33 | ";
34 | string payload = @"HTTP/1.1 200 OK
35 | Accept-Ranges: bytes
36 | Content-Length: " + System.Text.ASCIIEncoding.Unicode.GetByteCount(document) + @"
37 | Connection: close
38 | Content-Type: text/html; charset=utf-8
39 |
40 | " + document;
41 |
42 | byte[] msg = new byte[System.Text.ASCIIEncoding.Unicode.GetByteCount(payload)];
43 | msg = Encoding.Default.GetBytes(payload);
44 | ns.Write(msg, 0, msg.Length);
45 |
46 | client.Close();
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/obj/project.assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "targets": {
4 | "net6.0": {}
5 | },
6 | "libraries": {},
7 | "projectFileDependencyGroups": {
8 | "net6.0": []
9 | },
10 | "packageFolders": {
11 | "/home/ubuntu/.nuget/packages/": {}
12 | },
13 | "project": {
14 | "version": "1.0.0",
15 | "restore": {
16 | "projectUniqueName": "/tmp/runtime/runtime.csproj",
17 | "projectName": "runtime",
18 | "projectPath": "/tmp/runtime/runtime.csproj",
19 | "packagesPath": "/home/ubuntu/.nuget/packages/",
20 | "outputPath": "/tmp/runtime/obj/",
21 | "projectStyle": "PackageReference",
22 | "configFilePaths": [
23 | "/home/ubuntu/.nuget/NuGet/NuGet.Config"
24 | ],
25 | "originalTargetFrameworks": [
26 | "net6.0"
27 | ],
28 | "sources": {
29 | "https://api.nuget.org/v3/index.json": {}
30 | },
31 | "frameworks": {
32 | "net6.0": {
33 | "targetAlias": "net6.0",
34 | "projectReferences": {}
35 | }
36 | },
37 | "warningProperties": {
38 | "warnAsError": [
39 | "NU1605"
40 | ]
41 | }
42 | },
43 | "frameworks": {
44 | "net6.0": {
45 | "targetAlias": "net6.0",
46 | "imports": [
47 | "net461",
48 | "net462",
49 | "net47",
50 | "net471",
51 | "net472",
52 | "net48"
53 | ],
54 | "assetTargetFallback": true,
55 | "warn": true,
56 | "frameworkReferences": {
57 | "Microsoft.NETCore.App": {
58 | "privateAssets": "all"
59 | }
60 | },
61 | "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/6.0.301/RuntimeIdentifierGraph.json"
62 | }
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/smoke/testdata/dotnet/obj/runtime.csproj.nuget.dgspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "format": 1,
3 | "restore": {
4 | "/tmp/runtime/runtime.csproj": {}
5 | },
6 | "projects": {
7 | "/tmp/runtime/runtime.csproj": {
8 | "version": "1.0.0",
9 | "restore": {
10 | "projectUniqueName": "/tmp/runtime/runtime.csproj",
11 | "projectName": "runtime",
12 | "projectPath": "/tmp/runtime/runtime.csproj",
13 | "packagesPath": "/home/ubuntu/.nuget/packages/",
14 | "outputPath": "/tmp/runtime/obj/",
15 | "projectStyle": "PackageReference",
16 | "configFilePaths": [
17 | "/home/ubuntu/.nuget/NuGet/NuGet.Config"
18 | ],
19 | "originalTargetFrameworks": [
20 | "net6.0"
21 | ],
22 | "sources": {
23 | "https://api.nuget.org/v3/index.json": {}
24 | },
25 | "frameworks": {
26 | "net6.0": {
27 | "targetAlias": "net6.0",
28 | "projectReferences": {}
29 | }
30 | },
31 | "warningProperties": {
32 | "warnAsError": [
33 | "NU1605"
34 | ]
35 | }
36 | },
37 | "frameworks": {
38 | "net6.0": {
39 | "targetAlias": "net6.0",
40 | "imports": [
41 | "net461",
42 | "net462",
43 | "net47",
44 | "net471",
45 | "net472",
46 | "net48"
47 | ],
48 | "assetTargetFallback": true,
49 | "warn": true,
50 | "frameworkReferences": {
51 | "Microsoft.NETCore.App": {
52 | "privateAssets": "all"
53 | }
54 | },
55 | "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/6.0.301/RuntimeIdentifierGraph.json"
56 | }
57 | }
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | - name: status/possible-priority
2 | description: This issue is ready to work and should be considered as a potential priority
3 | color: F9D0C4
4 | - name: status/prioritized
5 | description: This issue has been triaged and resolving it is a priority
6 | color: BFD4F2
7 | - name: status/blocked
8 | description: This issue has been triaged and resolving it is blocked on some other issue
9 | color: 848978
10 | - name: bug
11 | description: Something isn't working
12 | color: d73a4a
13 | - name: enhancement
14 | description: A new feature or request
15 | color: a2eeef
16 | - name: documentation
17 | description: This issue relates to writing documentation
18 | color: D4C5F9
19 | - name: help wanted
20 | description: Extra attention is needed
21 | color: 008672
22 | - name: semver:major
23 | description: A change requiring a major version bump
24 | color: 6b230e
25 | - name: semver:minor
26 | description: A change requiring a minor version bump
27 | color: cc6749
28 | - name: semver:patch
29 | description: A change requiring a patch version bump
30 | color: f9d0c4
31 | - name: good first issue
32 | description: A good first issue to get started with
33 | color: d3fc03
34 | - name: "failure:release"
35 | description: An issue filed automatically when a release workflow run fails
36 | color: f00a0a
37 | - name: "failure:push"
38 | description: An issue filed automatically when a push buildpackage workflow run fails
39 | color: f00a0a
40 | - name: "failure:update-builder-toml"
41 | description: An issue filed automatically when a builder.toml update workflow run fails
42 | color: f00a0a
43 | - name: "failure:update-github-config"
44 | description: An issue filed automatically when a github config update workflow run fails
45 | color: f00a0a
46 | - name: "failure:approve-bot-pr"
47 | description: An issue filed automatically when a PR auto-approve workflow run fails
48 | color: f00a0a
49 |
--------------------------------------------------------------------------------
/smoke/dotnet_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testDotnet(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Dotnet app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "dotnet"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithEnv(map[string]string{"PORT": "8080"}).
66 | WithPublish("8080").
67 | Execute(image.ID)
68 | Expect(err).NotTo(HaveOccurred())
69 |
70 | Eventually(container).Should(BeAvailable())
71 |
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for ASP.NET Core Runtime")))
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for .NET Execute")))
74 | })
75 | })
76 | }
77 |
--------------------------------------------------------------------------------
/smoke/procfile_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testProcfile(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Procfile app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "procfile"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Procfile")))
65 |
66 | container, err = docker.Container.Run.
67 | WithEnv(map[string]string{"PORT": "8080"}).
68 | WithPublish("8080").
69 | Execute(image.ID)
70 | Expect(err).NotTo(HaveOccurred())
71 |
72 | Eventually(container).Should(BeAvailable())
73 | Eventually(container).Should(Serve(ContainSubstring("Hello World!")).OnPort(8080).WithEndpoint("/hello-world.txt"))
74 | })
75 | })
76 | }
77 |
--------------------------------------------------------------------------------
/smoke/go_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testGo(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Go app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "go"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithEnv(map[string]string{"PORT": "8080"}).
66 | WithPublish("8080").
67 | Execute(image.ID)
68 | Expect(err).NotTo(HaveOccurred())
69 |
70 | Eventually(container).Should(BeAvailable())
71 |
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Go Distribution")))
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Go Mod Vendor")))
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Go Build")))
75 | })
76 | })
77 | }
78 |
--------------------------------------------------------------------------------
/smoke/nodejs_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testNodejs(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Nodejs app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "nodejs"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithEnv(map[string]string{"PORT": "8080"}).
66 | WithPublish("8080").
67 | Execute(image.ID)
68 | Expect(err).NotTo(HaveOccurred())
69 |
70 | Eventually(container).Should(BeAvailable())
71 |
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Node Engine")))
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for NPM Install")))
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for NPM Start")))
75 | })
76 | })
77 | }
78 |
--------------------------------------------------------------------------------
/smoke/ruby_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testRuby(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Ruby app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "ruby"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithPublish("9292").
66 | Execute(image.ID)
67 | Expect(err).NotTo(HaveOccurred())
68 |
69 | Eventually(container).Should(BeAvailable())
70 |
71 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for MRI")))
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Bundler")))
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Bundle Install")))
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Puma")))
75 | })
76 | })
77 | }
78 |
--------------------------------------------------------------------------------
/smoke/python_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testPython(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Python app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "python"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithEnv(map[string]string{"PORT": "8080"}).
66 | WithPublish("8080").
67 | Execute(image.ID)
68 | Expect(err).NotTo(HaveOccurred())
69 |
70 | Eventually(container).Should(BeAvailable())
71 |
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for CPython")))
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Pipenv")))
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Pipenv Install")))
75 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Python Start")))
76 | })
77 | })
78 | }
79 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 | 4.0.0
7 |
8 | org.springframework.boot
9 | spring-boot-starter-parent
10 | 3.0.1
11 |
12 |
13 | io.paketo
14 | demo
15 | 0.0.1-SNAPSHOT
16 | demo
17 | Demo project for Spring Boot
18 |
19 | 17
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-actuator
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-webflux
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-test
34 | test
35 |
36 |
37 | io.projectreactor
38 | reactor-test
39 | test
40 |
41 |
42 |
43 |
44 |
45 | org.graalvm.buildtools
46 | native-maven-plugin
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-maven-plugin
51 |
52 | ${repackage.classifier}
53 |
54 | apps/native-image
55 | paketobuildpacks/builder:tiny
56 |
57 | true
58 | 17
59 | false
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/smoke/testdata/nginx/mime.types:
--------------------------------------------------------------------------------
1 | types {
2 | text/html html htm shtml;
3 | text/css css;
4 | text/xml xml;
5 | image/gif gif;
6 | image/jpeg jpeg jpg;
7 | application/x-javascript js;
8 | application/atom+xml atom;
9 | application/rss+xml rss;
10 | font/ttf ttf;
11 | font/woff woff;
12 | font/woff2 woff2;
13 | text/mathml mml;
14 | text/plain txt;
15 | text/vnd.sun.j2me.app-descriptor jad;
16 | text/vnd.wap.wml wml;
17 | text/x-component htc;
18 | text/cache-manifest manifest;
19 | image/png png;
20 | image/tiff tif tiff;
21 | image/vnd.wap.wbmp wbmp;
22 | image/x-icon ico;
23 | image/x-jng jng;
24 | image/x-ms-bmp bmp;
25 | image/svg+xml svg svgz;
26 | image/webp webp;
27 | application/java-archive jar war ear;
28 | application/mac-binhex40 hqx;
29 | application/msword doc;
30 | application/pdf pdf;
31 | application/postscript ps eps ai;
32 | application/rtf rtf;
33 | application/vnd.ms-excel xls;
34 | application/vnd.ms-powerpoint ppt;
35 | application/vnd.wap.wmlc wmlc;
36 | application/vnd.google-earth.kml+xml kml;
37 | application/vnd.google-earth.kmz kmz;
38 | application/x-7z-compressed 7z;
39 | application/x-cocoa cco;
40 | application/x-java-archive-diff jardiff;
41 | application/x-java-jnlp-file jnlp;
42 | application/x-makeself run;
43 | application/x-perl pl pm;
44 | application/x-pilot prc pdb;
45 | application/x-rar-compressed rar;
46 | application/x-redhat-package-manager rpm;
47 | application/x-sea sea;
48 | application/x-shockwave-flash swf;
49 | application/x-stuffit sit;
50 | application/x-tcl tcl tk;
51 | application/x-x509-ca-cert der pem crt;
52 | application/x-xpinstall xpi;
53 | application/xhtml+xml xhtml;
54 | application/zip zip;
55 | application/octet-stream bin exe dll;
56 | application/octet-stream deb;
57 | application/octet-stream dmg;
58 | application/octet-stream eot;
59 | application/octet-stream iso img;
60 | application/octet-stream msi msp msm;
61 | application/json json;
62 | audio/midi mid midi kar;
63 | audio/mpeg mp3;
64 | audio/ogg ogg;
65 | audio/x-m4a m4a;
66 | audio/x-realaudio ra;
67 | video/3gpp 3gpp 3gp;
68 | video/mp4 mp4;
69 | video/mpeg mpeg mpg;
70 | video/quicktime mov;
71 | video/webm webm;
72 | video/x-flv flv;
73 | video/x-m4v m4v;
74 | video/x-mng mng;
75 | video/x-ms-asf asx asf;
76 | video/x-ms-wmv wmv;
77 | video/x-msvideo avi;
78 | }
79 |
--------------------------------------------------------------------------------
/smoke/java_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testJava(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Java app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | // this is OK, the app also works for running with a JVM
55 | source, err = occam.Source(filepath.Join("testdata", "java-native-image"))
56 | Expect(err).NotTo(HaveOccurred())
57 |
58 | var logs fmt.Stringer
59 | image, logs, err = pack.Build.
60 | WithPullPolicy("always").
61 | WithBuilder(Builder).
62 | WithEnv(map[string]string{"BP_JVM_VERSION": "17"}).
63 | Execute(name, source)
64 | Expect(err).ToNot(HaveOccurred(), logs.String)
65 |
66 | container, err = docker.Container.Run.
67 | WithEnv(map[string]string{"PORT": "8080"}).
68 | WithPublish("8080").
69 | Execute(image.ID)
70 | Expect(err).NotTo(HaveOccurred())
71 |
72 | Eventually(container).Should(BeAvailable())
73 |
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for BellSoft Liberica")))
75 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Maven")))
76 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Executable JAR")))
77 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Spring Boot")))
78 | })
79 | })
80 | }
81 |
--------------------------------------------------------------------------------
/.github/workflows/test-builder.yml:
--------------------------------------------------------------------------------
1 | name: Test Builder
2 |
3 | on:
4 | workflow_dispatch: {}
5 |
6 | env:
7 | BUILDERS_FILEPATH: "builders.json"
8 |
9 | jobs:
10 | preparation:
11 | name: Preparation
12 | runs-on: ubuntu-24.04
13 | outputs:
14 | combos: ${{ steps.get_combos.outputs.combos }}
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v6
18 |
19 | - name: Get Combos
20 | id: get_combos
21 | run: |
22 | builders=$(jq -n -c '[]')
23 |
24 | if [ -f ${{ env.BUILDERS_FILEPATH }} ]; then
25 | builders=$(jq -c '.builders' ${{ env.BUILDERS_FILEPATH }})
26 | else
27 | # Strip off the Github org prefix from repo name
28 | # paketo-buildpacks/builder-with-some-name --> builder-with-some-name
29 | registry_repo=$(echo "${{ github.repository }}" | sed 's/^.*\///')
30 | builders=$(jq -n -c '[
31 | {
32 | "name": "'"${registry_repo}"'",
33 | "path": ".",
34 | "container_repository": "'"${registry_repo}"'",
35 | "test_runners": ["ubuntu-24.04"]
36 | }
37 | ]')
38 | fi
39 |
40 | builders=$(jq -c '.[]' <<< "$builders")
41 |
42 | combos=$(jq -n -c '[]')
43 |
44 | for builder in $builders; do
45 | runners=$(echo $builder | jq -r '.test_runners[]')
46 | builder_name=$(echo $builder | jq -r '.name')
47 | builder_path=$(echo $builder | jq -r '.path')
48 | for runner in $runners; do
49 | combos=$(
50 | jq \
51 | --arg builder_name "$builder_name" \
52 | --arg runner "$runner" \
53 | --arg builder_path "$builder_path" \
54 | '. + [{"builder": $builder_name, "runner": $runner, "path": $builder_path}]' \
55 | <<< "$combos"
56 | )
57 | done
58 | done
59 |
60 | combos=$(jq -c <<< "$combos")
61 | echo "combos=$combos"
62 | echo "combos=$combos" >> "$GITHUB_OUTPUT"
63 |
64 | smoke:
65 | name: Smoke Test
66 | needs: preparation
67 | strategy:
68 | matrix:
69 | combos: ${{ fromJSON(needs.preparation.outputs.combos) }}
70 | runs-on: ${{ matrix.combos.runner }}
71 |
72 | steps:
73 | - name: Checkout
74 | uses: actions/checkout@v6
75 |
76 | - name: Setup Go
77 | uses: actions/setup-go@v6
78 | with:
79 | go-version-file: go.mod
80 |
81 | - name: Run Smoke Tests
82 | run: ./scripts/smoke.sh --builder-dir "${{ matrix.combos.path }}"
83 |
--------------------------------------------------------------------------------
/smoke/java_native_image_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testJavaNativeImage(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a Java Native Image app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "java-native-image"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | WithEnv(map[string]string{"BP_NATIVE_IMAGE": "true", "BP_JVM_VERSION": "17", "BP_MAVEN_BUILD_ARGUMENTS": "-Pnative --batch-mode -Dmaven.test.skip=true --no-transfer-progress package", "USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM": "false"}).
62 | Execute(name, source)
63 | Expect(err).ToNot(HaveOccurred(), logs.String)
64 |
65 | container, err = docker.Container.Run.
66 | WithEnv(map[string]string{"PORT": "8080"}).
67 | WithPublish("8080").
68 | Execute(image.ID)
69 | Expect(err).NotTo(HaveOccurred())
70 |
71 | Eventually(container).Should(BeAvailable())
72 |
73 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for BellSoft Liberica")))
74 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Maven")))
75 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Executable JAR")))
76 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Spring Boot")))
77 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Native Image")))
78 | })
79 | })
80 | }
81 |
--------------------------------------------------------------------------------
/.github/workflows/update-github-config.yml:
--------------------------------------------------------------------------------
1 | name: Update shared github-config
2 |
3 | on:
4 | schedule:
5 | - cron: '47 8 * * *' # daily at 08:46 UTC
6 | workflow_dispatch: {}
7 |
8 | concurrency: github_config_update
9 |
10 | jobs:
11 | build:
12 | name: Create PR to update shared files
13 | runs-on: ubuntu-24.04
14 | steps:
15 |
16 | - name: Checkout
17 | uses: actions/checkout@v6
18 | with:
19 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
20 |
21 | - name: Checkout github-config
22 | uses: actions/checkout@v6
23 | with:
24 | repository: paketo-buildpacks/github-config
25 | path: github-config
26 |
27 | - name: Checkout Branch
28 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main
29 | with:
30 | branch: automation/github-config/update
31 |
32 | - name: Run the sync action
33 | uses: paketo-buildpacks/github-config/actions/sync@main
34 | with:
35 | workspace: /github/workspace
36 | config: /github/workspace/github-config/builder
37 |
38 | - name: Cleanup
39 | run: rm -rf github-config
40 |
41 | - name: Commit
42 | id: commit
43 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main
44 | with:
45 | message: "Updating github-config"
46 | pathspec: "."
47 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }}
48 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }}
49 |
50 | - name: Push Branch
51 | if: ${{ steps.commit.outputs.commit_sha != '' }}
52 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main
53 | with:
54 | branch: automation/github-config/update
55 |
56 | - name: Open Pull Request
57 | if: ${{ steps.commit.outputs.commit_sha != '' }}
58 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main
59 | with:
60 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
61 | title: "Updates github-config"
62 | branch: automation/github-config/update
63 |
64 | failure:
65 | name: Alert on Failure
66 | runs-on: ubuntu-24.04
67 | needs: [build]
68 | if: ${{ always() && needs.build.result == 'failure' }}
69 | steps:
70 | - name: File Failure Alert Issue
71 | uses: paketo-buildpacks/github-config/actions/issue/file@main
72 | with:
73 | token: ${{ secrets.GITHUB_TOKEN }}
74 | repo: ${{ github.repository }}
75 | label: "failure:update-github-config"
76 | comment_if_exists: true
77 | issue_title: "Failure: Update GitHub config workflow"
78 | issue_body: |
79 | Update GitHub config workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
80 | comment_body: |
81 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
82 |
--------------------------------------------------------------------------------
/.github/workflows/approve-bot-pr.yml:
--------------------------------------------------------------------------------
1 | name: Approve Bot PRs and Enable Auto-Merge
2 |
3 | on:
4 | workflow_run:
5 | workflows: ["Test Pull Request"]
6 | types:
7 | - completed
8 |
9 | jobs:
10 | download:
11 | name: Download PR Artifact
12 | if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
13 | runs-on: ubuntu-24.04
14 | outputs:
15 | pr-author: ${{ steps.pr-data.outputs.author }}
16 | pr-number: ${{ steps.pr-data.outputs.number }}
17 | steps:
18 | - name: 'Download artifact'
19 | uses: paketo-buildpacks/github-config/actions/pull-request/download-artifact@main
20 | with:
21 | name: "event-payload"
22 | repo: ${{ github.repository }}
23 | run_id: ${{ github.event.workflow_run.id }}
24 | workspace: "/github/workspace"
25 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
26 | - id: pr-data
27 | run: |
28 | echo "author=$(jq -r '.pull_request.user.login' event.json)" >> "$GITHUB_OUTPUT"
29 | echo "number=$(jq -r '.pull_request.number' event.json)" >> "$GITHUB_OUTPUT"
30 |
31 | approve:
32 | name: Approve Bot PRs
33 | needs: download
34 | if: ${{ needs.download.outputs.pr-author == 'paketo-bot' || needs.download.outputs.pr-author == 'dependabot[bot]' }}
35 | runs-on: ubuntu-24.04
36 | steps:
37 | - name: Check Commit Verification
38 | id: unverified-commits
39 | uses: paketo-buildpacks/github-config/actions/pull-request/check-unverified-commits@main
40 | with:
41 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }}
42 | repo: ${{ github.repository }}
43 | number: ${{ needs.download.outputs.pr-number }}
44 |
45 | - name: Check for Human Commits
46 | id: human-commits
47 | uses: paketo-buildpacks/github-config/actions/pull-request/check-human-commits@main
48 | with:
49 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }}
50 | repo: ${{ github.repository }}
51 | number: ${{ needs.download.outputs.pr-number }}
52 |
53 | - name: Checkout
54 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false'
55 | uses: actions/checkout@v6
56 |
57 | - name: Approve
58 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false'
59 | uses: paketo-buildpacks/github-config/actions/pull-request/approve@main
60 | with:
61 | token: ${{ secrets.PAKETO_BOT_REVIEWER_GITHUB_TOKEN }}
62 | number: ${{ needs.download.outputs.pr-number }}
63 |
64 | - name: Enable Auto-Merge
65 | if: steps.human-commits.outputs.human_commits == 'false' && steps.unverified-commits.outputs.unverified_commits == 'false'
66 | run: |
67 | gh pr merge ${{ needs.download.outputs.pr-number }} --auto --rebase
68 | env:
69 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
70 |
--------------------------------------------------------------------------------
/scripts/publish.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | readonly PROGDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7 | readonly ROOT_DIR="$(cd "${PROGDIR}/.." && pwd)"
8 | readonly BIN_DIR="${ROOT_DIR}/.bin"
9 |
10 | # shellcheck source=SCRIPTDIR/.util/tools.sh
11 | source "${PROGDIR}/.util/tools.sh"
12 |
13 | # shellcheck source=SCRIPTDIR/.util/print.sh
14 | source "${PROGDIR}/.util/print.sh"
15 |
16 | if [[ $BASH_VERSINFO -lt 4 ]]; then
17 | util::print::error "Before running this script please update Bash to v4 or higher (e.g. on OSX: \$ brew install bash)"
18 | fi
19 |
20 | function main() {
21 | local token
22 | local builder_toml_path=""
23 | local builder_image_ref=""
24 | token=""
25 |
26 | while [[ "${#}" != 0 ]]; do
27 | case "${1}" in
28 | --help|-h)
29 | shift 1
30 | usage
31 | exit 0
32 | ;;
33 |
34 | --builder-toml-path)
35 | builder_toml_path=${2}
36 | shift 2
37 | ;;
38 |
39 | --builder-image-ref)
40 | builder_image_ref=${2}
41 | shift 2
42 | ;;
43 |
44 | --token|-t)
45 | token="${2}"
46 | shift 2
47 | ;;
48 |
49 | "")
50 | # skip if the argument is empty
51 | shift 1
52 | ;;
53 |
54 | *)
55 | util::print::error "unknown argument \"${1}\""
56 | esac
57 | done
58 |
59 |
60 | if [ -z "$builder_toml_path" ]; then
61 | util::print::error "--builder-toml-path is required [Example: ./builders/builder/builder.toml]"
62 | fi
63 |
64 | if [ ! -f "$builder_toml_path" ]; then
65 | util::print::error "The provided --builder-toml-path does not exist or is not a file: $builder_toml_path"
66 | fi
67 |
68 | if [ -z "$builder_image_ref" ]; then
69 | util::print::error "--builder-image-ref is required [Example: index.docker.io/username/builder:tag or localhost:5000/builder:tag]"
70 | fi
71 |
72 | tools::install "${token}"
73 |
74 | builder::publish "$builder_toml_path" "$builder_image_ref"
75 | }
76 |
77 | function usage() {
78 | cat <<-USAGE
79 | publish.sh [OPTIONS]
80 |
81 | --builder-toml-path PATH Path to the builder.toml file that defines the builder to be published, e.g. ./builders/builder/builder.toml
82 | --builder-image-ref IMAGE_REF Full image name of the registry to push the built builder to, e.g. index.docker.io/username/builder:tag or localhost:5000/builder:tag
83 | --help, -h Show this help message
84 | USAGE
85 | }
86 |
87 | function tools::install() {
88 | local token
89 | token="${1}"
90 |
91 | util::tools::pack::install \
92 | --directory "${ROOT_DIR}/.bin" \
93 | --token "${token}"
94 | }
95 |
96 | function builder::publish() {
97 | local builder_toml_path="$1"
98 | local builder_image_ref="$2"
99 |
100 | util::print::title "Publishing builder image ${builder_image_ref} using builder config ${builder_toml_path}..."
101 | pack builder create "${builder_image_ref}" \
102 | --config "${builder_toml_path}" \
103 | --publish
104 | }
105 |
106 |
107 |
108 | main "${@:-}"
109 |
--------------------------------------------------------------------------------
/.github/workflows/test-pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Test Pull Request
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | env:
8 | BUILDERS_FILEPATH: "builders.json"
9 |
10 | jobs:
11 | preparation:
12 | name: Preparation
13 | runs-on: ubuntu-24.04
14 | outputs:
15 | combos: ${{ steps.get_combos.outputs.combos }}
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@v6
19 |
20 | - name: Get Combos
21 | id: get_combos
22 | run: |
23 | builders=$(jq -n -c '[]')
24 |
25 | if [ -f ${{ env.BUILDERS_FILEPATH }} ]; then
26 | builders=$(jq -c '.builders' ${{ env.BUILDERS_FILEPATH }})
27 | else
28 | # Strip off the Github org prefix from repo name
29 | # paketo-buildpacks/builder-with-some-name --> builder-with-some-name
30 | registry_repo=$(echo "${{ github.repository }}" | sed 's/^.*\///')
31 | builders=$(jq -n -c '[
32 | {
33 | "name": "'"${registry_repo}"'",
34 | "path": ".",
35 | "container_repository": "'"${registry_repo}"'",
36 | "test_runners": ["ubuntu-24.04"]
37 | }
38 | ]')
39 | fi
40 |
41 | builders=$(jq -c '.[]' <<< "$builders")
42 |
43 | combos=$(jq -n -c '[]')
44 |
45 | for builder in $builders; do
46 | runners=$(echo $builder | jq -r '.test_runners[]')
47 | builder_name=$(echo $builder | jq -r '.name')
48 | builder_path=$(echo $builder | jq -r '.path')
49 | for runner in $runners; do
50 | combos=$(
51 | jq \
52 | --arg builder_name "$builder_name" \
53 | --arg runner "$runner" \
54 | --arg builder_path "$builder_path" \
55 | '. + [{"builder": $builder_name, "runner": $runner, "path": $builder_path}]' \
56 | <<< "$combos"
57 | )
58 | done
59 | done
60 |
61 | combos=$(jq -c <<< "$combos")
62 | echo "combos=$combos"
63 | echo "combos=$combos" >> "$GITHUB_OUTPUT"
64 |
65 | smoke:
66 | name: Smoke Test
67 | needs: preparation
68 | strategy:
69 | matrix:
70 | combos: ${{ fromJSON(needs.preparation.outputs.combos) }}
71 | runs-on: ${{ matrix.combos.runner }}
72 |
73 | steps:
74 | - name: Checkout
75 | uses: actions/checkout@v6
76 |
77 | - name: Setup Go
78 | uses: actions/setup-go@v6
79 | with:
80 | go-version-file: go.mod
81 |
82 | - name: Run Smoke Tests
83 | run: ./scripts/smoke.sh --builder-dir "${{ matrix.combos.path }}"
84 |
85 | roundup:
86 | name: Smoke Test
87 | if: ${{ always() }}
88 | runs-on: ubuntu-24.04
89 | needs: smoke
90 | steps:
91 | - run: |
92 | result="${{ needs.smoke.result }}"
93 | if [[ $result == "success" ]]; then
94 | echo "Smoke tests passed against all builders"
95 | exit 0
96 | else
97 | echo "Smoke tests failed on one or more builders"
98 | exit 1
99 | fi
100 |
101 | upload:
102 | name: Upload Workflow Event Payload
103 | runs-on: ubuntu-24.04
104 | steps:
105 | - name: Upload Artifact
106 | uses: actions/upload-artifact@v6
107 | with:
108 | name: event-payload
109 | path: ${{ github.event_path }}
110 |
--------------------------------------------------------------------------------
/.github/workflows/update-go-mod-version.yml:
--------------------------------------------------------------------------------
1 | name: Update Go version
2 |
3 | on:
4 | schedule:
5 | - cron: '53 5 * * MON' # every monday at 5:53 UTC
6 | workflow_dispatch:
7 |
8 | concurrency: update-go
9 |
10 | jobs:
11 | update-go:
12 | name: Update go toolchain in go.mod
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Check out code
16 | uses: actions/checkout@v6
17 | - name: Checkout PR Branch
18 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main
19 | with:
20 | branch: automation/go-mod-update/update-main
21 | - name: Setup Go
22 | id: setup-go
23 | uses: actions/setup-go@v6
24 | # Fetching the latest stable Go version
25 | with:
26 | go-version: stable
27 | - name: Get current go toolchain version
28 | id: current-go-version
29 | uses: paketo-buildpacks/github-config/actions/update-go-mod-version@main
30 | with:
31 | go-version: ${{ steps.setup-go.outputs.go-version }}
32 | - name: Go mod tidy
33 | run: |
34 | #!/usr/bin/env bash
35 | set -euo pipefail
36 | shopt -s inherit_errexit
37 |
38 | echo "Before running go mod tidy"
39 | echo "head -n10 go.mod "
40 | head -n10 go.mod
41 |
42 | echo "git diff"
43 | git diff
44 |
45 | echo "Running go mod tidy"
46 | go mod tidy
47 |
48 | echo "After running go mod tidy"
49 | echo "head -n10 go.mod "
50 | head -n10 go.mod
51 |
52 | echo "git diff"
53 | git diff
54 | - name: Commit
55 | id: commit
56 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main
57 | with:
58 | message: "Updates go mod version to ${{ steps.setup-go.outputs.go-version }}"
59 | pathspec: "."
60 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }}
61 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }}
62 |
63 | - name: Push Branch
64 | if: ${{ steps.commit.outputs.commit_sha != '' }}
65 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main
66 | with:
67 | branch: automation/go-mod-update/update-main
68 |
69 | - name: Open Pull Request
70 | if: ${{ steps.commit.outputs.commit_sha != '' }}
71 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main
72 | with:
73 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
74 | title: "Updates go mod version to ${{ steps.setup-go.outputs.go-version }}"
75 | branch: automation/go-mod-update/update-main
76 |
77 | failure:
78 | name: Alert on Failure
79 | runs-on: ubuntu-24.04
80 | needs: [update-go]
81 | if: ${{ always() && needs.update-go.result == 'failure' }}
82 | steps:
83 | - name: File Failure Alert Issue
84 | uses: paketo-buildpacks/github-config/actions/issue/file@main
85 | with:
86 | token: ${{ secrets.GITHUB_TOKEN }}
87 | repo: ${{ github.repository }}
88 | label: "failure:update-go-version"
89 | comment_if_exists: true
90 | issue_title: "Failure: Update Go Mod Version workflow"
91 | issue_body: |
92 | Update Go Mod Version workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
93 | comment_body: |
94 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
95 |
--------------------------------------------------------------------------------
/smoke/testdata/httpd/httpd.conf:
--------------------------------------------------------------------------------
1 | ServerRoot "${SERVER_ROOT}"
2 | Listen "${PORT}"
3 | ServerAdmin "test@example.com"
4 | ServerName "0.0.0.0"
5 | DocumentRoot "${APP_ROOT}/htdocs"
6 |
7 | LoadModule authz_core_module modules/mod_authz_core.so
8 | LoadModule authz_host_module modules/mod_authz_host.so
9 | LoadModule log_config_module modules/mod_log_config.so
10 | LoadModule env_module modules/mod_env.so
11 | LoadModule setenvif_module modules/mod_setenvif.so
12 | LoadModule dir_module modules/mod_dir.so
13 | LoadModule mime_module modules/mod_mime.so
14 | LoadModule reqtimeout_module modules/mod_reqtimeout.so
15 | LoadModule unixd_module modules/mod_unixd.so
16 | LoadModule mpm_event_module modules/mod_mpm_event.so
17 | LoadModule remoteip_module modules/mod_remoteip.so
18 | LoadModule rewrite_module modules/mod_rewrite.so
19 | LoadModule filter_module modules/mod_filter.so
20 | LoadModule deflate_module modules/mod_deflate.so
21 | LoadModule headers_module modules/mod_headers.so
22 |
23 |
24 | AllowOverride none
25 | Require all denied
26 |
27 |
28 |
29 | Options SymLinksIfOwnerMatch
30 | AllowOverride All
31 | Require all granted
32 |
33 |
34 |
35 | Require all denied
36 |
37 |
38 |
39 | DirectoryIndex index.html
40 |
41 |
42 | TypesConfig conf/mime.types
43 | AddType application/x-compress .Z
44 | AddType application/x-gzip .gz .tgz
45 |
46 |
47 |
48 |
49 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
50 |
51 |
52 |
53 | ErrorLog "/proc/self/fd/2"
54 | LogLevel info
55 |
56 | LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
57 | LogFormat "%a %l %u %t \"%r\" %>s %b" common
58 | LogFormat "%a %l %u %t \"%r\" %>s %b vcap_request_id=%{X-Vcap-Request-Id}i peer_addr=%{c}a" extended
59 |
60 | LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
61 |
62 | CustomLog "/proc/self/fd/1" extended
63 |
64 |
65 |
66 | PidFile "/tmp/httpd.pid"
67 |
68 |
69 | StartServers 3
70 | MinSpareThreads 75
71 | MaxSpareThreads 250
72 | ThreadsPerChild 25
73 | MaxRequestWorkers 400
74 | MaxConnectionsPerChild 0
75 |
76 |
77 | StartServers 3
78 | MinSpareThreads 75
79 | MaxSpareThreads 250
80 | ThreadsPerChild 25
81 | MaxRequestWorkers 400
82 | MaxConnectionsPerChild 0
83 |
84 |
85 | MaxMemFree 2048
86 |
87 |
88 | Timeout 60
89 | KeepAlive On
90 | MaxKeepAliveRequests 100
91 | KeepAliveTimeout 5
92 | UseCanonicalName Off
93 | UseCanonicalPhysicalPort Off
94 | AccessFileName .htaccess
95 | ServerTokens Prod
96 | ServerSignature Off
97 | HostnameLookups Off
98 | EnableMMAP Off
99 | EnableSendfile On
100 | RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
101 |
102 | # Adjust IP Address based on header set by proxy
103 | #
104 | RemoteIpHeader x-forwarded-for
105 | RemoteIpInternalProxy 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
106 |
107 | # Set HTTPS environment variable if we came in over secure
108 | # channel.
109 | SetEnvIf x-forwarded-proto https HTTPS=on
110 |
111 |
112 | LoadModule headers_module modules/mod_headers.so
113 |
114 |
115 | RequestHeader unset Proxy early
116 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/paketo-buildpacks/builder-jammy-base
2 |
3 | go 1.25.5
4 |
5 | require (
6 | github.com/onsi/gomega v1.38.3
7 | github.com/paketo-buildpacks/occam v0.31.0
8 | github.com/sclevine/spec v1.4.0
9 | )
10 |
11 | require (
12 | dario.cat/mergo v1.0.2 // indirect
13 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
14 | github.com/BurntSushi/toml v1.5.0 // indirect
15 | github.com/Microsoft/go-winio v0.6.2 // indirect
16 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect
17 | github.com/containerd/errdefs v1.0.0 // indirect
18 | github.com/containerd/errdefs/pkg v0.3.0 // indirect
19 | github.com/containerd/log v0.1.0 // indirect
20 | github.com/containerd/platforms v0.2.1 // indirect
21 | github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
22 | github.com/cpuguy83/dockercfg v0.3.2 // indirect
23 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
24 | github.com/distribution/reference v0.6.0 // indirect
25 | github.com/docker/docker v28.5.1+incompatible // indirect
26 | github.com/docker/go-connections v0.6.0 // indirect
27 | github.com/docker/go-units v0.5.0 // indirect
28 | github.com/ebitengine/purego v0.8.4 // indirect
29 | github.com/felixge/httpsnoop v1.0.4 // indirect
30 | github.com/gabriel-vasile/mimetype v1.4.9 // indirect
31 | github.com/go-logr/logr v1.4.3 // indirect
32 | github.com/go-logr/stdr v1.2.2 // indirect
33 | github.com/go-ole/go-ole v1.3.0 // indirect
34 | github.com/google/go-cmp v0.7.0 // indirect
35 | github.com/google/go-containerregistry v0.20.6 // indirect
36 | github.com/google/uuid v1.6.0 // indirect
37 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
38 | github.com/klauspost/compress v1.18.0 // indirect
39 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
40 | github.com/magiconair/properties v1.8.10 // indirect
41 | github.com/moby/docker-image-spec v1.3.1 // indirect
42 | github.com/moby/go-archive v0.1.0 // indirect
43 | github.com/moby/patternmatcher v0.6.0 // indirect
44 | github.com/moby/sys/sequential v0.6.0 // indirect
45 | github.com/moby/sys/user v0.4.0 // indirect
46 | github.com/moby/sys/userns v0.1.0 // indirect
47 | github.com/moby/term v0.5.2 // indirect
48 | github.com/morikuni/aec v1.0.0 // indirect
49 | github.com/oklog/ulid v1.3.1 // indirect
50 | github.com/oklog/ulid/v2 v2.1.1 // indirect
51 | github.com/opencontainers/go-digest v1.0.0 // indirect
52 | github.com/opencontainers/image-spec v1.1.1 // indirect
53 | github.com/paketo-buildpacks/freezer v0.2.2 // indirect
54 | github.com/paketo-buildpacks/packit/v2 v2.25.2 // indirect
55 | github.com/pkg/errors v0.9.1 // indirect
56 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
57 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
58 | github.com/shirou/gopsutil/v4 v4.25.6 // indirect
59 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
60 | github.com/stretchr/testify v1.10.0 // indirect
61 | github.com/testcontainers/testcontainers-go v0.39.0 // indirect
62 | github.com/tklauser/go-sysconf v0.3.15 // indirect
63 | github.com/tklauser/numcpus v0.10.0 // indirect
64 | github.com/ulikunitz/xz v0.5.15 // indirect
65 | github.com/vbatts/tar-split v0.12.1 // indirect
66 | github.com/yusufpapurcu/wmi v1.2.4 // indirect
67 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect
68 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
69 | go.opentelemetry.io/otel v1.37.0 // indirect
70 | go.opentelemetry.io/otel/metric v1.37.0 // indirect
71 | go.opentelemetry.io/otel/trace v1.37.0 // indirect
72 | go.yaml.in/yaml/v3 v3.0.4 // indirect
73 | golang.org/x/crypto v0.42.0 // indirect
74 | golang.org/x/net v0.44.0 // indirect
75 | golang.org/x/sync v0.17.0 // indirect
76 | golang.org/x/sys v0.36.0 // indirect
77 | golang.org/x/text v0.29.0 // indirect
78 | gopkg.in/yaml.v3 v3.0.1 // indirect
79 | )
80 |
--------------------------------------------------------------------------------
/.github/workflows/push-image.yml:
--------------------------------------------------------------------------------
1 | name: Push Builder Image
2 |
3 | on:
4 | release:
5 | types:
6 | - published
7 |
8 | env:
9 | BUILDERS_FILEPATH: "builders.json"
10 |
11 | jobs:
12 | preparation:
13 | name: Preparation
14 | runs-on: ubuntu-24.04
15 | outputs:
16 | builders: ${{ steps.get-builders.outputs.builders }}
17 | tag: ${{ steps.event.outputs.tag }}
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v6
21 |
22 | - name: Get Builders
23 | id: get-builders
24 | run: |
25 | builders=$(jq -n -c '[]')
26 |
27 | if [ -f ${{ env.BUILDERS_FILEPATH }} ]; then
28 | builders=$(jq -c '.builders' ${{ env.BUILDERS_FILEPATH }})
29 | else
30 | # Strip off the Github org prefix from repo name
31 | # paketo-buildpacks/builder-with-some-name --> builder-with-some-name
32 | registry_repo=$(echo "${{ github.repository }}" | sed 's/^.*\///')
33 | builders=$(jq -n -c '[
34 | {
35 | "name": "'"${registry_repo}"'",
36 | "path": ".",
37 | "container_repository": "'"${registry_repo}"'"
38 | }
39 | ]')
40 | fi
41 |
42 | # Filter only the necessary fields
43 | builders=$(echo "$builders" | jq 'map({
44 | name,
45 | path,
46 | container_repository
47 | })')
48 |
49 | builders=$(jq -c <<< "$builders")
50 | echo "builders=$builders"
51 | echo "builders=$builders" >> "$GITHUB_OUTPUT"
52 |
53 | - name: Parse Event
54 | id: event
55 | run: |
56 | echo "tag=$(jq -r '.release.tag_name' "${GITHUB_EVENT_PATH}" | sed s/^v//)" >> "$GITHUB_OUTPUT"
57 |
58 | push:
59 | name: Push
60 | needs: preparation
61 | runs-on: ubuntu-24.04
62 | strategy:
63 | matrix:
64 | builders: ${{ fromJSON(needs.preparation.outputs.builders) }}
65 | steps:
66 |
67 | - name: Checkout
68 | uses: actions/checkout@v6
69 |
70 | - name: Create Builder Image and Push To Dockerhub
71 | env:
72 | PAKETO_BUILDPACKS_DOCKERHUB_USERNAME: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_USERNAME }}
73 | PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD: ${{ secrets.PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD }}
74 | GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
75 | run: |
76 | # shellcheck source=./scripts/.util/tools.sh
77 | source "./scripts/.util/tools.sh"
78 |
79 | util::tools::crane::install --directory "./.bin"
80 |
81 | DOCKERHUB_ORG="${GITHUB_REPOSITORY_OWNER/-/}" # translates 'paketo-buildpacks' to 'paketobuildpacks'
82 | container_repository=${{ matrix.builders.container_repository }}
83 |
84 | echo "${PAKETO_BUILDPACKS_DOCKERHUB_PASSWORD}" | docker login --username "${PAKETO_BUILDPACKS_DOCKERHUB_USERNAME}" --password-stdin
85 |
86 | ./scripts/publish.sh --builder-toml-path "${{ matrix.builders.path }}/builder.toml" \
87 | --builder-image-ref "${DOCKERHUB_ORG}/${container_repository}:${{ needs.preparation.outputs.tag }}"
88 |
89 | ./.bin/crane copy "${DOCKERHUB_ORG}/${container_repository}:${{ needs.preparation.outputs.tag }}" "${DOCKERHUB_ORG}/${container_repository}:latest"
90 |
91 | failure:
92 | name: Alert on Failure
93 | runs-on: ubuntu-24.04
94 | needs: [push]
95 | if: ${{ always() && needs.push.result == 'failure' }}
96 | steps:
97 | - name: File Failure Alert Issue
98 | uses: paketo-buildpacks/github-config/actions/issue/file@main
99 | with:
100 | token: ${{ secrets.GITHUB_TOKEN }}
101 | repo: ${{ github.repository }}
102 | label: "failure:push"
103 | comment_if_exists: true
104 | issue_title: "Failure: Push Image workflow"
105 | issue_body: |
106 | Push Image workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
107 | comment_body: |
108 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
109 |
--------------------------------------------------------------------------------
/.github/workflows/update-builder-toml.yml:
--------------------------------------------------------------------------------
1 | name: Update builder.toml files and Send Pull Request
2 |
3 | on:
4 | schedule:
5 | - cron: '27 2,14 * * *' # daily at 02:27 and 14:27 UTC
6 | workflow_dispatch: {}
7 |
8 | concurrency: builder_update
9 |
10 | env:
11 | BUILDERS_FILEPATH: "builders.json"
12 |
13 | jobs:
14 | preparation:
15 | name: Preparation
16 | runs-on: ubuntu-24.04
17 | outputs:
18 | builders: ${{ steps.get-builders.outputs.builders }}
19 | steps:
20 | - name: Checkout
21 | uses: actions/checkout@v6
22 |
23 | - name: Get Builders
24 | id: get-builders
25 | run: |
26 | builders=$(jq -n -c '[]')
27 |
28 | if [ -f ${{ env.BUILDERS_FILEPATH }} ]; then
29 | builders=$(jq -c '.builders' ${{ env.BUILDERS_FILEPATH }})
30 | else
31 | # Strip off the Github org prefix from repo name
32 | # paketo-buildpacks/builder-with-some-name --> builder-with-some-name
33 | registry_repo=$(echo "${{ github.repository }}" | sed 's/^.*\///')
34 | builders=$(jq -n -c '[
35 | {
36 | "name": "'"${registry_repo}"'",
37 | "path": ".",
38 | "container_repository": "'"${registry_repo}"'"
39 | }
40 | ]')
41 | fi
42 |
43 | # Filter only the necessary fields
44 | builders=$(echo "$builders" | jq 'map({
45 | name,
46 | path,
47 | container_repository
48 | })')
49 |
50 | builders=$(jq -c <<< "$builders")
51 | echo "builders=$builders"
52 | echo "builders=$builders" >> "$GITHUB_OUTPUT"
53 |
54 | update:
55 | name: Update builder.toml
56 | runs-on: ubuntu-24.04
57 | outputs:
58 | commit_sha: ${{ steps.commit.outputs.commit_sha }}
59 | needs: preparation
60 | strategy:
61 | max-parallel: 1
62 | matrix:
63 | builders: ${{ fromJSON(needs.preparation.outputs.builders) }}
64 |
65 | steps:
66 | - name: Check out
67 | uses: actions/checkout@v6
68 |
69 | - name: Checkout branch
70 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main
71 | with:
72 | branch: "automation/builder-toml-update"
73 |
74 | - name: Update builder.toml
75 | uses: paketo-buildpacks/github-config/actions/builder/update@main
76 | with:
77 | token: ${{ secrets.GITHUB_TOKEN }}
78 | filename: "${{ matrix.builders.path }}/builder.toml"
79 |
80 | - name: Git commit
81 | id: commit
82 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main
83 | with:
84 | message: "Update ${{ matrix.builders.name }} builder.toml"
85 | pathspec: "${{ matrix.builders.path }}/builder.toml"
86 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }}
87 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }}
88 |
89 | - name: Git push
90 | if: ${{ steps.commit.outputs.commit_sha != '' }}
91 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main
92 | with:
93 | branch: "automation/builder-toml-update"
94 |
95 | - name: Output commit sha
96 | if: ${{ steps.commit.outputs.commit_sha != '' }}
97 | run: echo "commit_sha=${{ steps.commit.outputs.commit_sha }}" >> "$GITHUB_OUTPUT"
98 |
99 | open-pull-request:
100 | name: Open pull request
101 | runs-on: ubuntu-24.04
102 | needs: update
103 | if: ${{ needs.update.outputs.commit_sha != '' }}
104 | steps:
105 | - name: Check out
106 | uses: actions/checkout@v6
107 |
108 | - name: Checkout branch
109 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main
110 | with:
111 | branch: "automation/builder-toml-update"
112 |
113 | - name: Open Pull Request
114 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main
115 | with:
116 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
117 | title: "Updating builder.toml files"
118 | branch: "automation/builder-toml-update"
119 |
120 | failure:
121 | name: Alert on Failure
122 | runs-on: ubuntu-24.04
123 | needs: [update, open-pull-request]
124 | if: ${{ always() && ( needs.update.result == 'failure' || needs.open-pull-request.result == 'failure' ) }}
125 | steps:
126 | - name: File Failure Alert Issue
127 | uses: paketo-buildpacks/github-config/actions/issue/file@main
128 | with:
129 | token: ${{ secrets.GITHUB_TOKEN }}
130 | repo: ${{ github.repository }}
131 | label: "failure:update-builder-toml"
132 | comment_if_exists: true
133 | issue_title: "Failure: Update Builder TOML workflow"
134 | issue_body: |
135 | Update Builder TOML workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
136 | comment_body: |
137 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
138 |
--------------------------------------------------------------------------------
/.github/workflows/update-test-data.yml:
--------------------------------------------------------------------------------
1 | name: Update test data from samples
2 |
3 | on:
4 | schedule:
5 | - cron: '46 4 * * *' # daily at 04:46 UTC
6 | workflow_dispatch: {}
7 |
8 | concurrency: test_data_update
9 |
10 | env:
11 | BUILDERS_FILEPATH: "builders.json"
12 |
13 | jobs:
14 | build:
15 | name: Create PR to sync test data with the samples
16 | runs-on: ubuntu-24.04
17 | steps:
18 |
19 | - name: Checkout
20 | uses: actions/checkout@v6
21 | with:
22 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
23 |
24 | - name: ${{ env.BUILDERS_FILEPATH }} exists
25 | id: builder_file_exists
26 | run: |
27 | if [ ! -f ${{ env.BUILDERS_FILEPATH }} ]; then
28 | echo "${{ env.BUILDERS_FILEPATH }} does not exist, skipping"
29 | echo "exists=false" >> $GITHUB_OUTPUT
30 | else
31 | echo "exists=true" >> $GITHUB_OUTPUT
32 | fi
33 |
34 | - name: Checkout paketo-buildpacks samples
35 | if: ${{ steps.builder_file_exists.outputs.exists == 'true' }}
36 | uses: actions/checkout@v6
37 | with:
38 | repository: paketo-buildpacks/samples
39 | path: samples
40 |
41 | - name: Checkout Branch
42 | if: ${{ steps.builder_file_exists.outputs.exists == 'true' }}
43 | uses: paketo-buildpacks/github-config/actions/pull-request/checkout-branch@main
44 | with:
45 | branch: automation/testdata/update
46 |
47 | - name: Run the sync action
48 | if: ${{ steps.builder_file_exists.outputs.exists == 'true' }}
49 | run: |
50 | builders=$(jq -c '.builders.[]' ${{ env.BUILDERS_FILEPATH }})
51 | for builder in $builders; do
52 | test_data=$(echo $builder | jq -c '.test_data // []' | jq -c '.[]')
53 | for td in $test_data; do
54 | sample_dir=$(echo $td | jq -r '.sample_dir // empty')
55 | if [ -z "$sample_dir" ]; then
56 | echo "sample_dir can not be empty"
57 | exit 1
58 | fi
59 |
60 | sample_dir="samples/${sample_dir}/"
61 |
62 | test_dir=$(echo $td | jq -r '.test_dir // empty')
63 | if [ -z "$test_dir" ]; then
64 | echo "test_dir can not be empty"
65 | exit 1
66 | fi
67 | test_dir="${test_dir}/"
68 |
69 | echo
70 | echo "syncing from ${sample_dir} to ${test_dir}"
71 | echo
72 |
73 | args=(
74 | --recursive
75 | "${sample_dir}"
76 | "${test_dir}"
77 | --delete
78 | )
79 |
80 | if [[ -f "${test_dir}/.syncignore" ]]; then
81 | args+=(
82 | --exclude=".syncignore"
83 | --exclude-from="${test_dir}/.syncignore"
84 | )
85 | fi
86 |
87 | rsync ${args[*]}
88 |
89 | echo
90 | echo "sync complete"
91 | echo
92 | done
93 | done
94 |
95 | - name: Cleanup
96 | if: ${{ steps.builder_file_exists.outputs.exists == 'true' }}
97 | run: rm -rf samples
98 |
99 | - name: Commit
100 | if: ${{ steps.builder_file_exists.outputs.exists == 'true' }}
101 | id: commit
102 | uses: paketo-buildpacks/github-config/actions/pull-request/create-commit@main
103 | with:
104 | message: "Updating test data from samples"
105 | pathspec: "."
106 | keyid: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY_ID }}
107 | key: ${{ secrets.PAKETO_BOT_GPG_SIGNING_KEY }}
108 |
109 | - name: Push Branch
110 | if: ${{ steps.commit.outputs.commit_sha != '' }}
111 | uses: paketo-buildpacks/github-config/actions/pull-request/push-branch@main
112 | with:
113 | branch: automation/testdata/update
114 |
115 | - name: Open Pull Request
116 | if: ${{ steps.commit.outputs.commit_sha != '' }}
117 | uses: paketo-buildpacks/github-config/actions/pull-request/open@main
118 | with:
119 | token: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
120 | title: "Updates test data from samples"
121 | branch: automation/testdata/update
122 | label: "semver:patch"
123 |
124 | failure:
125 | name: Alert on Failure
126 | runs-on: ubuntu-24.04
127 | needs: [build]
128 | if: ${{ always() && needs.build.result == 'failure' }}
129 | steps:
130 | - name: File Failure Alert Issue
131 | uses: paketo-buildpacks/github-config/actions/issue/file@main
132 | with:
133 | token: ${{ secrets.GITHUB_TOKEN }}
134 | repo: ${{ github.repository }}
135 | label: "failure:update-github-config"
136 | comment_if_exists: true
137 | issue_title: "Failure: Update GitHub config workflow"
138 | issue_body: |
139 | Update GitHub config workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
140 | comment_body: |
141 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
142 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | import java.net.*;
17 | import java.io.*;
18 | import java.nio.channels.*;
19 | import java.util.Properties;
20 |
21 | public class MavenWrapperDownloader {
22 |
23 | private static final String WRAPPER_VERSION = "0.5.6";
24 | /**
25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26 | */
27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29 |
30 | /**
31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32 | * use instead of the default one.
33 | */
34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35 | ".mvn/wrapper/maven-wrapper.properties";
36 |
37 | /**
38 | * Path where the maven-wrapper.jar will be saved to.
39 | */
40 | private static final String MAVEN_WRAPPER_JAR_PATH =
41 | ".mvn/wrapper/maven-wrapper.jar";
42 |
43 | /**
44 | * Name of the property which should be used to override the default download url for the wrapper.
45 | */
46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47 |
48 | public static void main(String args[]) {
49 | System.out.println("- Downloader started");
50 | File baseDirectory = new File(args[0]);
51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52 |
53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
54 | // wrapperUrl parameter.
55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56 | String url = DEFAULT_DOWNLOAD_URL;
57 | if(mavenWrapperPropertyFile.exists()) {
58 | FileInputStream mavenWrapperPropertyFileInputStream = null;
59 | try {
60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61 | Properties mavenWrapperProperties = new Properties();
62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64 | } catch (IOException e) {
65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66 | } finally {
67 | try {
68 | if(mavenWrapperPropertyFileInputStream != null) {
69 | mavenWrapperPropertyFileInputStream.close();
70 | }
71 | } catch (IOException e) {
72 | // Ignore ...
73 | }
74 | }
75 | }
76 | System.out.println("- Downloading from: " + url);
77 |
78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79 | if(!outputFile.getParentFile().exists()) {
80 | if(!outputFile.getParentFile().mkdirs()) {
81 | System.out.println(
82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83 | }
84 | }
85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86 | try {
87 | downloadFileFromURL(url, outputFile);
88 | System.out.println("Done");
89 | System.exit(0);
90 | } catch (Throwable e) {
91 | System.out.println("- Error downloading");
92 | e.printStackTrace();
93 | System.exit(1);
94 | }
95 | }
96 |
97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99 | String username = System.getenv("MVNW_USERNAME");
100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101 | Authenticator.setDefault(new Authenticator() {
102 | @Override
103 | protected PasswordAuthentication getPasswordAuthentication() {
104 | return new PasswordAuthentication(username, password);
105 | }
106 | });
107 | }
108 | URL website = new URL(urlString);
109 | ReadableByteChannel rbc;
110 | rbc = Channels.newChannel(website.openStream());
111 | FileOutputStream fos = new FileOutputStream(destination);
112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113 | fos.close();
114 | rbc.close();
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/smoke/web_servers_test.go:
--------------------------------------------------------------------------------
1 | package smoke_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | "testing"
8 |
9 | "github.com/paketo-buildpacks/occam"
10 | "github.com/sclevine/spec"
11 |
12 | . "github.com/onsi/gomega"
13 | . "github.com/paketo-buildpacks/occam/matchers"
14 | )
15 |
16 | func testWebServers(t *testing.T, context spec.G, it spec.S) {
17 | var (
18 | Expect = NewWithT(t).Expect
19 | Eventually = NewWithT(t).Eventually
20 |
21 | pack occam.Pack
22 | docker occam.Docker
23 | )
24 |
25 | it.Before(func() {
26 | pack = occam.NewPack().WithVerbose().WithNoColor()
27 | docker = occam.NewDocker()
28 | })
29 |
30 | context("detects a HTTPD app", func() {
31 | var (
32 | image occam.Image
33 | container occam.Container
34 |
35 | name string
36 | source string
37 | )
38 |
39 | it.Before(func() {
40 | var err error
41 | name, err = occam.RandomName()
42 | Expect(err).NotTo(HaveOccurred())
43 | })
44 |
45 | it.After(func() {
46 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
47 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
48 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
49 | Expect(os.RemoveAll(source)).To(Succeed())
50 | })
51 |
52 | it("builds successfully", func() {
53 | var err error
54 | source, err = occam.Source(filepath.Join("testdata", "httpd"))
55 | Expect(err).NotTo(HaveOccurred())
56 |
57 | var logs fmt.Stringer
58 | image, logs, err = pack.Build.
59 | WithPullPolicy("always").
60 | WithBuilder(Builder).
61 | Execute(name, source)
62 | Expect(err).ToNot(HaveOccurred(), logs.String)
63 |
64 | container, err = docker.Container.Run.
65 | WithEnv(map[string]string{"PORT": "8080"}).
66 | WithPublish("8080").
67 | Execute(image.ID)
68 | Expect(err).NotTo(HaveOccurred())
69 |
70 | Eventually(container).Should(BeAvailable())
71 |
72 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Apache HTTP Server")))
73 | })
74 | })
75 |
76 | context("detects a NGINX app", func() {
77 | var (
78 | image occam.Image
79 | container occam.Container
80 |
81 | name string
82 | source string
83 | )
84 |
85 | it.Before(func() {
86 | var err error
87 | name, err = occam.RandomName()
88 | Expect(err).NotTo(HaveOccurred())
89 | })
90 |
91 | it.After(func() {
92 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
93 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
94 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
95 | Expect(os.RemoveAll(source)).To(Succeed())
96 | })
97 |
98 | it("builds successfully", func() {
99 | var err error
100 | source, err = occam.Source(filepath.Join("testdata", "nginx"))
101 | Expect(err).NotTo(HaveOccurred())
102 |
103 | var logs fmt.Stringer
104 | image, logs, err = pack.Build.
105 | WithPullPolicy("always").
106 | WithBuilder(Builder).
107 | Execute(name, source)
108 | Expect(err).ToNot(HaveOccurred(), logs.String)
109 |
110 | container, err = docker.Container.Run.
111 | WithEnv(map[string]string{"PORT": "8080"}).
112 | WithPublish("8080").
113 | Execute(image.ID)
114 | Expect(err).NotTo(HaveOccurred())
115 |
116 | Eventually(container).Should(BeAvailable())
117 |
118 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Nginx Server")))
119 | })
120 | })
121 |
122 | context("detects a JavaScript frontend app", func() {
123 | var (
124 | image occam.Image
125 | container occam.Container
126 |
127 | name string
128 | source string
129 | )
130 |
131 | it.Before(func() {
132 | var err error
133 | name, err = occam.RandomName()
134 | Expect(err).NotTo(HaveOccurred())
135 | })
136 |
137 | it.After(func() {
138 | Expect(docker.Container.Remove.Execute(container.ID)).To(Succeed())
139 | Expect(docker.Volume.Remove.Execute(occam.CacheVolumeNames(name))).To(Succeed())
140 | Expect(docker.Image.Remove.Execute(image.ID)).To(Succeed())
141 | Expect(os.RemoveAll(source)).To(Succeed())
142 | })
143 |
144 | context("app uses react and httpd", func() {
145 | it("builds successfully", func() {
146 | var err error
147 | source, err = occam.Source(filepath.Join("testdata", "javascript-frontend"))
148 | Expect(err).NotTo(HaveOccurred())
149 |
150 | var logs fmt.Stringer
151 | image, logs, err = pack.Build.
152 | WithPullPolicy("always").
153 | WithBuilder(Builder).
154 | WithEnv(map[string]string{
155 | "BP_NODE_RUN_SCRIPTS": "build",
156 | "BP_WEB_SERVER": "httpd",
157 | "BP_WEB_SERVER_ROOT": "build",
158 | "BP_WEB_SERVER_ENABLE_PUSH_STATE": "true",
159 | }).
160 | Execute(name, source)
161 | Expect(err).ToNot(HaveOccurred(), logs.String)
162 |
163 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Node Engine")))
164 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for NPM Install")))
165 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Node Run Script")))
166 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Apache HTTP Server")))
167 |
168 | container, err = docker.Container.Run.
169 | WithEnv(map[string]string{"PORT": "8080"}).
170 | WithPublish("8080").
171 | Execute(image.ID)
172 | Expect(err).NotTo(HaveOccurred())
173 |
174 | Eventually(container).Should(Serve(ContainSubstring("Paketo Buildpacks")).OnPort(8080))
175 | })
176 | })
177 |
178 | context("app uses react and nginx", func() {
179 | it("builds successfully", func() {
180 | var err error
181 | source, err = occam.Source(filepath.Join("testdata", "javascript-frontend"))
182 | Expect(err).NotTo(HaveOccurred())
183 |
184 | var logs fmt.Stringer
185 | image, logs, err = pack.Build.
186 | WithPullPolicy("always").
187 | WithBuilder(Builder).
188 | WithEnv(map[string]string{
189 | "BP_NODE_RUN_SCRIPTS": "build",
190 | "BP_WEB_SERVER": "nginx",
191 | "BP_WEB_SERVER_ROOT": "build",
192 | "BP_WEB_SERVER_ENABLE_PUSH_STATE": "true",
193 | }).
194 | Execute(name, source)
195 | Expect(err).ToNot(HaveOccurred(), logs.String)
196 |
197 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Node Engine")))
198 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for NPM Install")))
199 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Node Run Script")))
200 | Expect(logs).To(ContainLines(ContainSubstring("Paketo Buildpack for Nginx Server")))
201 |
202 | container, err = docker.Container.Run.
203 | WithEnv(map[string]string{"PORT": "8080"}).
204 | WithPublish("8080").
205 | Execute(image.ID)
206 | Expect(err).NotTo(HaveOccurred())
207 |
208 | Eventually(container).Should(Serve(ContainSubstring("Paketo Buildpacks")).OnPort(8080))
209 | })
210 | })
211 | })
212 | }
213 |
--------------------------------------------------------------------------------
/scripts/.util/tools.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | # shellcheck source=SCRIPTDIR/print.sh
7 | source "$(dirname "${BASH_SOURCE[0]}")/print.sh"
8 |
9 | function util::tools::os() {
10 | case "$(uname)" in
11 | "Darwin")
12 | echo "${1:-darwin}"
13 | ;;
14 |
15 | "Linux")
16 | echo "linux"
17 | ;;
18 |
19 | *)
20 | util::print::error "Unknown OS \"$(uname)\""
21 | exit 1
22 | esac
23 | }
24 |
25 | function util::tools::arch() {
26 | case "$(uname -m)" in
27 | arm64|aarch64)
28 | echo "arm64"
29 | ;;
30 |
31 | amd64|x86_64)
32 | if [[ "${1:-}" == "--blank-amd64" ]]; then
33 | echo ""
34 | elif [[ "${1:-}" == "--uname-format-amd64" ]]; then
35 | echo "x86_64"
36 | else
37 | echo "amd64"
38 | fi
39 | ;;
40 |
41 | *)
42 | util::print::error "Unknown Architecture \"$(uname -m)\""
43 | exit 1
44 | esac
45 | }
46 |
47 | function util::tools::path::export() {
48 | local dir
49 | dir="${1}"
50 |
51 | if ! echo "${PATH}" | grep -q "${dir}"; then
52 | PATH="${dir}:$PATH"
53 | export PATH
54 | fi
55 | }
56 |
57 | function util::tools::jam::install() {
58 | local dir token
59 | token=""
60 |
61 | while [[ "${#}" != 0 ]]; do
62 | case "${1}" in
63 | --directory)
64 | dir="${2}"
65 | shift 2
66 | ;;
67 |
68 | --token)
69 | token="${2}"
70 | shift 2
71 | ;;
72 |
73 | *)
74 | util::print::error "unknown argument \"${1}\""
75 | esac
76 | done
77 |
78 | mkdir -p "${dir}"
79 | util::tools::path::export "${dir}"
80 |
81 | if [[ ! -f "${dir}/jam" ]]; then
82 | local version curl_args os arch
83 |
84 | version="$(jq -r .jam "$(dirname "${BASH_SOURCE[0]}")/tools.json")"
85 |
86 | curl_args=(
87 | "--fail"
88 | "--silent"
89 | "--location"
90 | "--output" "${dir}/jam"
91 | )
92 |
93 | if [[ "${token}" != "" ]]; then
94 | curl_args+=("--header" "Authorization: Token ${token}")
95 | fi
96 |
97 | util::print::title "Installing jam ${version}"
98 |
99 | os=$(util::tools::os)
100 | arch=$(util::tools::arch)
101 |
102 | curl "https://github.com/paketo-buildpacks/jam/releases/download/${version}/jam-${os}-${arch}" \
103 | "${curl_args[@]}"
104 |
105 | chmod +x "${dir}/jam"
106 | else
107 | util::print::info "Using $("${dir}"/jam version)"
108 | fi
109 | }
110 |
111 | function util::tools::pack::install() {
112 | local dir token
113 | token=""
114 |
115 | while [[ "${#}" != 0 ]]; do
116 | case "${1}" in
117 | --directory)
118 | dir="${2}"
119 | shift 2
120 | ;;
121 |
122 | --token)
123 | token="${2}"
124 | shift 2
125 | ;;
126 |
127 | *)
128 | util::print::error "unknown argument \"${1}\""
129 | esac
130 | done
131 |
132 | mkdir -p "${dir}"
133 | util::tools::path::export "${dir}"
134 |
135 | if [[ ! -f "${dir}/pack" ]]; then
136 | local version curl_args os arch
137 |
138 | version="$(jq -r .pack "$(dirname "${BASH_SOURCE[0]}")/tools.json")"
139 |
140 | local pack_config_enable_experimental
141 | if [ -f "$(dirname "${BASH_SOURCE[0]}")/../options.json" ]; then
142 | pack_config_enable_experimental="$(jq -r .pack_config_enable_experimental "$(dirname "${BASH_SOURCE[0]}")/../options.json")"
143 | else
144 | pack_config_enable_experimental="false"
145 | fi
146 |
147 | tmp_location="/tmp/pack.tgz"
148 | curl_args=(
149 | "--fail"
150 | "--silent"
151 | "--location"
152 | "--output" "${tmp_location}"
153 | )
154 |
155 | if [[ "${token}" != "" ]]; then
156 | curl_args+=("--header" "Authorization: Token ${token}")
157 | fi
158 |
159 | util::print::title "Installing pack ${version}"
160 |
161 | os=$(util::tools::os macos)
162 | arch=$(util::tools::arch --blank-amd64)
163 |
164 | curl "https://github.com/buildpacks/pack/releases/download/${version}/pack-${version}-${os}${arch:+-$arch}.tgz" \
165 | "${curl_args[@]}"
166 |
167 | tar xzf "${tmp_location}" -C "${dir}"
168 | chmod +x "${dir}/pack"
169 |
170 | if [[ "${pack_config_enable_experimental}" == "true" ]]; then
171 | "${dir}"/pack config experimental true
172 | fi
173 |
174 | rm "${tmp_location}"
175 | else
176 | util::print::info "Using pack $("${dir}"/pack version)"
177 | fi
178 | }
179 |
180 | function util::tools::tests::checkfocus() {
181 | testout="${1}"
182 | if grep -q 'Focused: [1-9]' "${testout}"; then
183 | echo "Detected Focused Test(s) - setting exit code to 197"
184 | rm "${testout}"
185 | util::print::success "** GO Test Succeeded **" 197
186 | fi
187 | rm "${testout}"
188 | }
189 |
190 | function util::tools::crane::install() {
191 | local dir token
192 | token=""
193 |
194 | while [[ "${#}" != 0 ]]; do
195 | case "${1}" in
196 | --directory)
197 | dir="${2}"
198 | shift 2
199 | ;;
200 |
201 | --token)
202 | token="${2}"
203 | shift 2
204 | ;;
205 |
206 | *)
207 | util::print::error "unknown argument \"${1}\""
208 | esac
209 | done
210 |
211 | mkdir -p "${dir}"
212 | util::tools::path::export "${dir}"
213 |
214 | if [[ ! -f "${dir}/crane" ]]; then
215 | local version curl_args os arch
216 |
217 | version="$(jq -r .crane "$(dirname "${BASH_SOURCE[0]}")/tools.json")"
218 |
219 | curl_args=(
220 | "--fail"
221 | "--silent"
222 | "--location"
223 | )
224 |
225 | if [[ "${token}" != "" ]]; then
226 | curl_args+=("--header" "Authorization: Token ${token}")
227 | fi
228 |
229 | util::print::title "Installing crane ${version}"
230 |
231 | os=$(util::tools::os)
232 | arch=$(util::tools::arch --uname-format-amd64)
233 |
234 |
235 | curl "https://github.com/google/go-containerregistry/releases/download/${version}/go-containerregistry_Linux_${arch}.tar.gz" \
236 | "${curl_args[@]}" | tar -C "${dir}" -xz crane
237 |
238 | chmod +x "${dir}/crane"
239 | fi
240 | }
241 |
242 |
243 | # Returns a random unused port
244 | function get::random::port() {
245 | local port=$(shuf -i 50000-65000 -n 1)
246 | netstat -lat | grep $port > /dev/null
247 | if [[ $? == 1 ]] ; then
248 | echo $port
249 | else
250 | echo get::random::port
251 | fi
252 | }
253 |
254 | # Starts a local registry on the given port and returns the pid
255 | function local::registry::start() {
256 | local registryPort registryPid localRegistry
257 |
258 | registryPort="$1"
259 | localRegistry="127.0.0.1:$registryPort"
260 |
261 | # Start a local in-memory registry so we can work with oci archives
262 | PORT=$registryPort crane registry serve --insecure > /dev/null 2>&1 &
263 | registryPid=$!
264 |
265 | # Stop the registry if execution is interrupted
266 | trap "kill $registryPid" 1 2 3 6
267 |
268 | # Wait for the registry to be available
269 | until crane catalog $localRegistry > /dev/null 2>&1; do
270 | sleep 1
271 | done
272 |
273 | echo $registryPid
274 | }
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
124 |
125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
162 | if ERRORLEVEL 1 goto error
163 | goto end
164 |
165 | :error
166 | set ERROR_CODE=1
167 |
168 | :end
169 | @endlocal & set ERROR_CODE=%ERROR_CODE%
170 |
171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
175 | :skipRcPost
176 |
177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
179 |
180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
181 |
182 | exit /B %ERROR_CODE%
183 |
--------------------------------------------------------------------------------
/scripts/smoke.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eu
4 | set -o pipefail
5 |
6 | readonly PROGDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7 | readonly ROOTDIR="$(cd "${PROGDIR}/.." && pwd)"
8 | readonly OPTIONS_JSON="${ROOTDIR}/scripts/options.json"
9 |
10 | # shellcheck source=SCRIPTDIR/.util/tools.sh
11 | source "${PROGDIR}/.util/tools.sh"
12 |
13 | # shellcheck source=SCRIPTDIR/.util/print.sh
14 | source "${PROGDIR}/.util/print.sh"
15 |
16 | function main() {
17 | local name token
18 | local registryPort registryPid localRegistryUrl pushBuilderToLocalRegistry
19 | local builderDir builderArray targetPlatform
20 | token=""
21 | registryPid=""
22 | builderDir=""
23 | builderArray=()
24 | targetPlatform=""
25 | localRegistryUrl=""
26 | pushBuilderToLocalRegistry=""
27 |
28 | while [[ "${#}" != 0 ]]; do
29 | case "${1}" in
30 | --help|-h)
31 | shift 1
32 | usage
33 | exit 0
34 | ;;
35 |
36 | --name|-n)
37 | name="${2}"
38 | shift 2
39 | ;;
40 |
41 | --builder-dir)
42 | builderDir="${2}"
43 | shift 2
44 | ;;
45 |
46 | --target-platform)
47 | targetPlatform="${2}"
48 | shift 2
49 | ;;
50 |
51 | --local-registry-url)
52 | localRegistryUrl="${2}"
53 | shift 2
54 | ;;
55 |
56 | --push-builder-to-local-registry)
57 | pushBuilderToLocalRegistry="${2}"
58 | shift 2
59 | ;;
60 |
61 | --token|-t)
62 | token="${2}"
63 | shift 2
64 | ;;
65 |
66 | "")
67 | # skip if the argument is empty
68 | shift 1
69 | ;;
70 |
71 | *)
72 | util::print::error "unknown argument \"${1}\""
73 | esac
74 | done
75 |
76 | if [[ -z "${targetPlatform}" ]]; then
77 | os=$(util::tools::os macos)
78 | arch=$(util::tools::arch)
79 | targetPlatform="${os}/${arch}"
80 | fi
81 |
82 | if [ -n "${builderDir}" ]; then
83 | if [[ -z "${name:-}" ]]; then
84 | name="testbuilder"
85 | util::print::info "Using default name for the builder: ${name}"
86 | fi
87 | builderArray+=($(jq -n --arg name "$name" --arg path "$builderDir" '{name: $name, path: $path}' | jq -c '.'))
88 | elif [[ -f ${ROOTDIR}/builders.json ]]; then
89 | builderArray=($(jq -r -c '.builders[]' ${ROOTDIR}/builders.json))
90 | else
91 | if [[ -z "${name:-}" ]]; then
92 | name="testbuilder"
93 | util::print::info "Using default name for the builder: ${name}"
94 | fi
95 | util::print::info "Using current directory as the builder directory."
96 | builderArray+=($(jq -n --arg name "$name" --arg path "$ROOTDIR" '{name: $name, path: $path}' | jq -c '.'))
97 | fi
98 |
99 | util::print::info "Found the following builder directories:"
100 | for builder in "${builderArray[@]}"; do
101 | builderName=$(jq -r '.name' <<<"${builder}")
102 | builderPath=$(jq -r '.path' <<<"${builder}")
103 | util::print::info " - Name: ${builderName}, Path: ${builderPath}"
104 | done
105 |
106 | tools::install "${token}"
107 |
108 | if [ "${pushBuilderToLocalRegistry}" != "" ]; then
109 | if [[ "${pushBuilderToLocalRegistry}" != "true" && "${pushBuilderToLocalRegistry}" != "false" ]]; then
110 | util::print::error "--push-builder-to-local-registry must be 'true' or 'false'"
111 | fi
112 | util::print::info "Using command line argument for push_builder_to_local_registry: ${pushBuilderToLocalRegistry}"
113 | elif [ -f $OPTIONS_JSON ]; then
114 | pushBuilderToLocalRegistry="$(jq -r '.push_builder_to_local_registry //false' $OPTIONS_JSON)"
115 | else
116 | pushBuilderToLocalRegistry="false"
117 | fi
118 |
119 | trap 'cleanup "$registryPid" "$builderName"' EXIT
120 |
121 | # Set up local registry to push the builder(s)
122 | if [[ "${pushBuilderToLocalRegistry}" == "true" && "${localRegistryUrl}" == "" ]]; then
123 | registryPort=$(get::random::port)
124 | registryPid=$(local::registry::start $registryPort)
125 | localRegistryUrl="127.0.0.1:$registryPort"
126 | util::print::info "Started local registry at ${localRegistryUrl} with PID ${registryPid}"
127 | fi
128 |
129 | local testout
130 | testout=$(mktemp)
131 | for builderDir in "${builderArray[@]}"; do
132 | builderName=$(jq -r '.name' <<<"${builderDir}")
133 | builderDir=$(jq -r '.path' <<<"${builderDir}")
134 |
135 | util::print::info "Running tests for builder: ${builderName}"
136 |
137 | if [[ ! -d "${builderDir}" ]]; then
138 | util::print::error "Builder directory ${builderDir} does not exist."
139 | fi
140 |
141 | if [[ ! -d "${builderDir}/smoke" ]]; then
142 | util::print::warn "** WARNING No Smoke tests **"
143 | fi
144 |
145 | builder::create "${builderName}" "${builderDir}" "${localRegistryUrl}" "${targetPlatform}"
146 |
147 | if [[ "${pushBuilderToLocalRegistry}" == "true" ]]; then
148 | builderName="$localRegistryUrl/$builderName"
149 | else
150 | builderName="$builderName"
151 | fi
152 |
153 | image::pull::lifecycle "${builderName}" "${pushBuilderToLocalRegistry}"
154 |
155 | tests::run "${builderName}" "${testout}"
156 | done
157 |
158 | util::tools::tests::checkfocus "${testout}"
159 | util::print::success "** GO Test Succeeded for all builders**"
160 | }
161 |
162 | function cleanup (){
163 | local registryPid builderName
164 | registryPid="${1}"
165 | builderName="${2}"
166 |
167 | if [[ "${registryPid}" != "" ]]; then
168 | kill "${registryPid}"
169 | fi
170 | if [[ "${builderName}" != "" ]]; then
171 | docker rmi "${builderName}" || true
172 | fi
173 | }
174 |
175 | function usage() {
176 | cat <<-USAGE
177 | smoke.sh [OPTIONS]
178 |
179 | Runs the smoke test suite.
180 |
181 | OPTIONS
182 | --help -h prints the command usage
183 | --name -n sets the name of the builder that is built for testing
184 | --token token used to download assets from GitHub (e.g. jam, pack, etc) (optional)
185 | --builder-dir sets the directory of the builder to test. Defaults to the current directory.
186 | --target-platform sets the target platform to build the builder image for. E.g. linux/amd64, linux/arm64, etc.
187 | Defaults host machine's OS/arch.
188 | --local-registry-url sets the local registry URL to push the builder image to. E.g. 127.0.0.1:5000
189 | --push-builder-to-local-registry if "true", pushes the builder image to a local registry.
190 | Defaults value false or the value in scripts/options.json if the file exists.
191 | Note: if true and --local-registry-url is not set, a local registry will be started on a random port.
192 | USAGE
193 | }
194 |
195 | function tools::install() {
196 | local token
197 | token="${1}"
198 |
199 | util::tools::crane::install \
200 | --directory "${ROOTDIR}/.bin" \
201 | --token "${token}"
202 |
203 | util::tools::pack::install \
204 | --directory "${ROOTDIR}/.bin" \
205 | --token "${token}"
206 | }
207 |
208 | function builder::create() {
209 | local builderName path localRegistryUrl
210 | builderName="${1}"
211 | path="${2}"
212 | localRegistryUrl="${3:-}"
213 | targetPlatform="${4}"
214 |
215 | if [[ "${localRegistryUrl}" != "" ]]; then
216 | util::print::title "Creating ${localRegistryUrl}/${builderName} builder image..."
217 | pack builder create "${localRegistryUrl}/${builderName}" --config "${path}/builder.toml" --target "${targetPlatform}" --publish
218 | else
219 | util::print::title "Creating ${builderName} builder image..."
220 | pack builder create "${builderName}" --config "${path}/builder.toml" --target "${targetPlatform}"
221 | fi
222 | }
223 |
224 | function image::pull::lifecycle() {
225 | local name lifecycle_image pushBuilderToLocalRegistry
226 | name="${1}"
227 | pushBuilderToLocalRegistry="${2:-false}"
228 |
229 | if [[ "${pushBuilderToLocalRegistry}" == "true" ]]; then
230 | lifecycle_image="index.docker.io/buildpacksio/lifecycle:$(
231 | pack builder inspect "${name}" --output json \
232 | | jq -r '.remote_info.lifecycle.version'
233 | )"
234 | else
235 | lifecycle_image="index.docker.io/buildpacksio/lifecycle:$(
236 | pack builder inspect "${name}" --output json \
237 | | jq -r '.local_info.lifecycle.version'
238 | )"
239 | fi
240 |
241 | util::print::title "Pulling lifecycle image..."
242 | docker pull "${lifecycle_image}"
243 | }
244 |
245 | function tests::run() {
246 | local name
247 | name="${1}"
248 |
249 | util::print::title "Run Builder Smoke Tests for ${name}..."
250 |
251 | export CGO_ENABLED=0
252 | pushd "${builderDir}" > /dev/null
253 | if GOMAXPROCS="${GOMAXPROCS:-4}" go test -count=1 -timeout 0 ./smoke/... -v -run Smoke --name "${name}" | tee "${testout}"; then
254 | util::print::info "** GO Test Succeeded with ${name} **"
255 | else
256 | util::print::error "** GO Test Failed with ${name} **"
257 | fi
258 | popd > /dev/null
259 | }
260 |
261 | main "${@:-}"
262 |
--------------------------------------------------------------------------------
/smoke/testdata/java-native-image/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Mingw, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | fi
118 |
119 | if [ -z "$JAVA_HOME" ]; then
120 | javaExecutable="`which javac`"
121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
122 | # readlink(1) is not available as standard on Solaris 10.
123 | readLink=`which readlink`
124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
125 | if $darwin ; then
126 | javaHome="`dirname \"$javaExecutable\"`"
127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
128 | else
129 | javaExecutable="`readlink -f \"$javaExecutable\"`"
130 | fi
131 | javaHome="`dirname \"$javaExecutable\"`"
132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
133 | JAVA_HOME="$javaHome"
134 | export JAVA_HOME
135 | fi
136 | fi
137 | fi
138 |
139 | if [ -z "$JAVACMD" ] ; then
140 | if [ -n "$JAVA_HOME" ] ; then
141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
142 | # IBM's JDK on AIX uses strange locations for the executables
143 | JAVACMD="$JAVA_HOME/jre/sh/java"
144 | else
145 | JAVACMD="$JAVA_HOME/bin/java"
146 | fi
147 | else
148 | JAVACMD="`which java`"
149 | fi
150 | fi
151 |
152 | if [ ! -x "$JAVACMD" ] ; then
153 | echo "Error: JAVA_HOME is not defined correctly." >&2
154 | echo " We cannot execute $JAVACMD" >&2
155 | exit 1
156 | fi
157 |
158 | if [ -z "$JAVA_HOME" ] ; then
159 | echo "Warning: JAVA_HOME environment variable is not set."
160 | fi
161 |
162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
163 |
164 | # traverses directory structure from process work directory to filesystem root
165 | # first directory with .mvn subdirectory is considered project base directory
166 | find_maven_basedir() {
167 |
168 | if [ -z "$1" ]
169 | then
170 | echo "Path not specified to find_maven_basedir"
171 | return 1
172 | fi
173 |
174 | basedir="$1"
175 | wdir="$1"
176 | while [ "$wdir" != '/' ] ; do
177 | if [ -d "$wdir"/.mvn ] ; then
178 | basedir=$wdir
179 | break
180 | fi
181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
182 | if [ -d "${wdir}" ]; then
183 | wdir=`cd "$wdir/.."; pwd`
184 | fi
185 | # end of workaround
186 | done
187 | echo "${basedir}"
188 | }
189 |
190 | # concatenates all lines of a file
191 | concat_lines() {
192 | if [ -f "$1" ]; then
193 | echo "$(tr -s '\n' ' ' < "$1")"
194 | fi
195 | }
196 |
197 | BASE_DIR=`find_maven_basedir "$(pwd)"`
198 | if [ -z "$BASE_DIR" ]; then
199 | exit 1;
200 | fi
201 |
202 | ##########################################################################################
203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
204 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
205 | ##########################################################################################
206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
207 | if [ "$MVNW_VERBOSE" = true ]; then
208 | echo "Found .mvn/wrapper/maven-wrapper.jar"
209 | fi
210 | else
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
213 | fi
214 | if [ -n "$MVNW_REPOURL" ]; then
215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
216 | else
217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
218 | fi
219 | while IFS="=" read key value; do
220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
221 | esac
222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
223 | if [ "$MVNW_VERBOSE" = true ]; then
224 | echo "Downloading from: $jarUrl"
225 | fi
226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
227 | if $cygwin; then
228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
229 | fi
230 |
231 | if command -v wget > /dev/null; then
232 | if [ "$MVNW_VERBOSE" = true ]; then
233 | echo "Found wget ... using wget"
234 | fi
235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
236 | wget "$jarUrl" -O "$wrapperJarPath"
237 | else
238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
239 | fi
240 | elif command -v curl > /dev/null; then
241 | if [ "$MVNW_VERBOSE" = true ]; then
242 | echo "Found curl ... using curl"
243 | fi
244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
245 | curl -o "$wrapperJarPath" "$jarUrl" -f
246 | else
247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
248 | fi
249 |
250 | else
251 | if [ "$MVNW_VERBOSE" = true ]; then
252 | echo "Falling back to using Java to download"
253 | fi
254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
255 | # For Cygwin, switch paths to Windows format before running javac
256 | if $cygwin; then
257 | javaClass=`cygpath --path --windows "$javaClass"`
258 | fi
259 | if [ -e "$javaClass" ]; then
260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
261 | if [ "$MVNW_VERBOSE" = true ]; then
262 | echo " - Compiling MavenWrapperDownloader.java ..."
263 | fi
264 | # Compiling the Java class
265 | ("$JAVA_HOME/bin/javac" "$javaClass")
266 | fi
267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
268 | # Running the downloader
269 | if [ "$MVNW_VERBOSE" = true ]; then
270 | echo " - Running MavenWrapperDownloader.java ..."
271 | fi
272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
273 | fi
274 | fi
275 | fi
276 | fi
277 | ##########################################################################################
278 | # End of extension
279 | ##########################################################################################
280 |
281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
282 | if [ "$MVNW_VERBOSE" = true ]; then
283 | echo $MAVEN_PROJECTBASEDIR
284 | fi
285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
286 |
287 | # For Cygwin, switch paths to Windows format before running java
288 | if $cygwin; then
289 | [ -n "$M2_HOME" ] &&
290 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
291 | [ -n "$JAVA_HOME" ] &&
292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
293 | [ -n "$CLASSPATH" ] &&
294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
295 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
297 | fi
298 |
299 | # Provide a "standardized" way to retrieve the CLI args that will
300 | # work with both Windows and non-Windows executions.
301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
302 | export MAVEN_CMD_LINE_ARGS
303 |
304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
305 |
306 | exec "$JAVACMD" \
307 | $MAVEN_OPTS \
308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
311 |
--------------------------------------------------------------------------------
/.github/workflows/create-release.yml:
--------------------------------------------------------------------------------
1 | name: Create Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | concurrency: release
9 |
10 | env:
11 | BUILDERS_FILEPATH: "builders.json"
12 |
13 | jobs:
14 | preparation:
15 | name: Preparation
16 | runs-on: ubuntu-24.04
17 | outputs:
18 | builders: ${{ steps.get-builders.outputs.builders }}
19 | combos: ${{ steps.get_combos.outputs.combos }}
20 | steps:
21 | - name: Checkout
22 | uses: actions/checkout@v6
23 |
24 | - name: Get Builders
25 | id: get-builders
26 | run: |
27 | builders=$(jq -n -c '[]')
28 |
29 | if [ -f ${{ env.BUILDERS_FILEPATH }} ]; then
30 | builders=$(jq -c '.builders' ${{ env.BUILDERS_FILEPATH }})
31 | else
32 | # Strip off the Github org prefix from repo name
33 | # paketo-buildpacks/builder-with-some-name --> builder-with-some-name
34 | registry_repo=$(echo "${{ github.repository }}" | sed 's/^.*\///')
35 | builders=$(jq -n -c '[
36 | {
37 | "name": "'"${registry_repo}"'",
38 | "path": ".",
39 | "container_repository": "'"${registry_repo}"'",
40 | "test_runners": ["ubuntu-24.04"]
41 | }
42 | ]')
43 | fi
44 |
45 | # Filter only the necessary fields
46 | builders=$(echo "$builders" | jq 'map({
47 | name,
48 | path,
49 | container_repository,
50 | test_runners
51 | })')
52 |
53 | builders=$(jq -c <<< "$builders")
54 | echo "builders=$builders"
55 | echo "builders=$builders" >> "$GITHUB_OUTPUT"
56 |
57 | - name: Get Combos
58 | id: get_combos
59 | run: |
60 | builders=$(echo '${{ steps.get-builders.outputs.builders }}' | jq -c '.[]')
61 | combos=$(jq -n -c '[]')
62 |
63 | for builder in $builders; do
64 | runners=$(echo $builder | jq -r '.test_runners[]')
65 | builder_name=$(echo $builder | jq -r '.name')
66 | builder_path=$(echo $builder | jq -r '.path')
67 | for runner in $runners; do
68 | combos=$(
69 | jq \
70 | --arg builder_name "$builder_name" \
71 | --arg runner "$runner" \
72 | --arg builder_path "$builder_path" \
73 | '. + [{"builder": $builder_name, "runner": $runner, "path": $builder_path}]' \
74 | <<< "$combos"
75 | )
76 | done
77 | done
78 |
79 | combos=$(jq -c <<< "$combos")
80 | echo "combos=$combos"
81 | echo "combos=$combos" >> "$GITHUB_OUTPUT"
82 |
83 | builder_files_changed:
84 | name: Builder Files Changed
85 | runs-on: ubuntu-24.04
86 | needs: preparation
87 | outputs:
88 | builders_changed: ${{ steps.compare_previous_release.outputs.builders_changed }}
89 | steps:
90 | - name: Checkout
91 | uses: actions/checkout@v6
92 | with:
93 | fetch-depth: 0 # gets full history
94 |
95 | - name: Compare previous releases
96 | id: compare_previous_release
97 | run: |
98 | builders=$(echo '${{ needs.preparation.outputs.builders }}' | jq -c '.[]')
99 | for builder in $builders; do
100 | builder_path=$(echo "$builder" | jq -r '.path')
101 |
102 | changed=$(git diff --name-only $(git describe --tags --abbrev=0) -- $builder_path/builder.toml)
103 | if [ -z "${changed}" ]
104 | then
105 | # We do not write on the github output because this step runs multiple times
106 | # and it might overwrite any true value written by the else statement.
107 | echo "No changes for $builder_path/builder.toml"
108 | else
109 | echo "Changes detected for $builder_path/builder.toml"
110 | echo "builders_changed=true" >> $GITHUB_OUTPUT
111 | fi
112 | done
113 |
114 | smoke:
115 | name: Smoke Test
116 | needs: [preparation, builder_files_changed]
117 | if: ${{ needs.builder_files_changed.outputs.builders_changed == 'true' }}
118 | strategy:
119 | matrix:
120 | combos: ${{ fromJSON(needs.preparation.outputs.combos) }}
121 | runs-on: ${{ matrix.combos.runner }}
122 |
123 | steps:
124 | - name: Checkout
125 | uses: actions/checkout@v6
126 |
127 | - name: Setup Go
128 | uses: actions/setup-go@v6
129 | with:
130 | go-version-file: go.mod
131 |
132 | - name: Run Smoke Tests
133 | run: ./scripts/smoke.sh --builder-dir "${{ matrix.combos.path }}"
134 |
135 | get_builders_info:
136 | name: Get Builders Info
137 | runs-on: ubuntu-24.04
138 | needs: [preparation, builder_files_changed, smoke]
139 | strategy:
140 | matrix:
141 | builders: ${{ fromJSON(needs.preparation.outputs.builders) }}
142 | services:
143 | registry:
144 | image: registry:3
145 | ports:
146 | - 5000:5000
147 | outputs:
148 | builder_info: ${{ steps.notes.outputs.body }}
149 | steps:
150 | - name: Checkout
151 | uses: actions/checkout@v6
152 |
153 | - name: Setup Go
154 | uses: actions/setup-go@v6
155 | with:
156 | go-version-file: go.mod
157 |
158 | - name: Get pack version
159 | id: pack-version
160 | run: |
161 | version=$(jq -r .pack "scripts/.util/tools.json")
162 | echo "version=${version#v}" >> "$GITHUB_OUTPUT"
163 |
164 | - name: Install Global Pack
165 | uses: buildpacks/github-actions/setup-pack@main
166 | with:
167 | pack-version: ${{ steps.pack-version.outputs.version }}
168 |
169 | - name: Builder info
170 | id: notes
171 | run: |
172 | registry_builder_name=localhost:5000/${{ matrix.builders.name }}
173 |
174 | ./scripts/publish.sh --builder-toml-path "${{ matrix.builders.path }}/builder.toml" \
175 | --builder-image-ref "${registry_builder_name}"
176 |
177 | pack inspect-builder $registry_builder_name | grep -v 'Inspecting builder' \
178 | | grep -v 'REMOTE:' \
179 | | grep -v 'LOCAL:' \
180 | | grep -v '\(not present\)' \
181 | | grep -v 'Warning' > "${{ matrix.builders.name }}-info.md"
182 |
183 | - name: Upload info for ${{ matrix.builders.name }}
184 | uses: actions/upload-artifact@v6
185 | with:
186 | name: "${{ matrix.builders.name }}-info.md"
187 | path: "${{ matrix.builders.name }}-info.md"
188 |
189 | release:
190 | name: Release
191 | runs-on: ubuntu-24.04
192 | needs: [preparation, get_builders_info]
193 | steps:
194 | - name: Checkout With History
195 | uses: actions/checkout@v6
196 | with:
197 | fetch-depth: 0 # gets full history
198 |
199 | - name: Download Release Note File(s)
200 | uses: actions/download-artifact@v7
201 | with:
202 | path: info
203 | pattern: "*info.md"
204 | merge-multiple: true
205 |
206 | - name: Generate Release Notes and Assets
207 | id: generate_release_notes_and_assets
208 | run: |
209 | set -euo pipefail
210 | shopt -s inherit_errexit
211 |
212 | builders=$(echo '${{ needs.preparation.outputs.builders }}' | jq -c '.[]')
213 | builders_length=$(echo '${{ needs.preparation.outputs.builders }}' | jq 'length')
214 |
215 | release_notes_dir="info"
216 |
217 | # Start with an empty array
218 | assets=$(jq -n -c '[]')
219 |
220 | # Generate release assets only if we have more than one builder
221 | if [ "$builders_length" -gt 1 ]; then
222 | for builder in $builders; do
223 | builder_name=$(echo "$builder" | jq -r '.name')
224 |
225 | assets="$(jq -c \
226 | --arg release_notes_dir "${release_notes_dir}" \
227 | --arg builder_name "${builder_name}" \
228 | '. += [
229 | {
230 | "path": ($release_notes_dir + "/" + $builder_name + "-" + "info.md"),
231 | "name": ($builder_name + "-" + "info.md"),
232 | "content_type": "text/markdown"
233 | }
234 | ]' <<<"${assets}")"
235 | done
236 | fi
237 |
238 | echo "assets=${assets}" >> "$GITHUB_OUTPUT"
239 |
240 | # translates 'paketo-buildpacks' to 'paketobuildpacks'
241 | DOCKERHUB_ORG="${GITHUB_REPOSITORY_OWNER/-/}"
242 |
243 | release_body=""
244 | if [ "$builders_length" -gt 1 ]; then
245 | for builder in $builders; do
246 | container_repository=$(echo "$builder" | jq -r '.container_repository')
247 | release_body+="Builder: \`${DOCKERHUB_ORG}/${container_repository}\`\n"
248 | done
249 | payload="{\"body\" : \"\n${release_body}\"}"
250 | else
251 | builder=$(echo "$builders" | head -n 1)
252 | release_body="$(cat $release_notes_dir/$(echo "$builder" | jq -r '.name')-info.md \
253 | | sed -e '/./,$!d' \
254 | | awk -F, '{printf "%s\\n", $0}')"
255 | payload="{\"body\" : \"\`\`\`\n${release_body}\n\`\`\`\"}"
256 | fi
257 |
258 | echo "release_body=${payload}" >> "$GITHUB_OUTPUT"
259 |
260 | - name: Publish Release
261 | id: publish
262 | uses: release-drafter/release-drafter@v6
263 | with:
264 | config-name: release-drafter-config.yml
265 | publish: true
266 | env:
267 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
268 |
269 | - name: Update Release Notes
270 | run: |
271 | set -euo pipefail
272 | shopt -s inherit_errexit
273 |
274 | payload='${{ steps.generate_release_notes_and_assets.outputs.release_body }}'
275 | curl --fail \
276 | -X PATCH \
277 | -H "Accept: application/vnd.github.v3+json" \
278 | -H "Authorization: token ${GITHUB_TOKEN}" \
279 | "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}" \
280 | -d "${payload}"
281 |
282 | assets='${{ steps.generate_release_notes_and_assets.outputs.assets }}'
283 |
284 | # Update release assets
285 | for row in $(echo "${assets}" | jq -c '.[]'); do
286 | path=$(echo "$row" | jq -r '.path')
287 | name=$(echo "$row" | jq -r '.name')
288 | content_type=$(echo "$row" | jq -r '.content_type')
289 |
290 | echo "Uploading asset: ${name} from path: ${path}"
291 |
292 | curl -L \
293 | -X POST \
294 | -H "Accept: application/vnd.github.v3+json" \
295 | -H "Authorization: token ${GITHUB_TOKEN}" \
296 | -H "Content-Type: ${content_type}" \
297 | "https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${name}" \
298 | --data-binary "@${path}"
299 | done
300 | env:
301 | RELEASE_ID: ${{ steps.publish.outputs.id }}
302 | GITHUB_TOKEN: ${{ secrets.PAKETO_BOT_GITHUB_TOKEN }}
303 |
304 | failure:
305 | name: Alert on Failure
306 | runs-on: ubuntu-24.04
307 | needs: [ smoke, release, get_builders_info, preparation ]
308 | if: ${{ always() && needs.smoke.result == 'failure' || needs.release.result == 'failure' || needs.get_builders_info.result == 'failure' || needs.preparation.result == 'failure' }}
309 | steps:
310 | - name: File Failure Alert Issue
311 | uses: paketo-buildpacks/github-config/actions/issue/file@main
312 | with:
313 | token: ${{ secrets.GITHUB_TOKEN }}
314 | repo: ${{ github.repository }}
315 | label: "failure:release"
316 | comment_if_exists: true
317 | issue_title: "Failure: Create Release workflow"
318 | issue_body: |
319 | Create Release workflow [failed](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
320 | comment_body: |
321 | Another failure occurred: https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
322 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
2 | dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
3 | github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
4 | github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
5 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
6 | github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
7 | github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
8 | github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
9 | github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
10 | github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
11 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
12 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
13 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
14 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
15 | github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
16 | github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
17 | github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
18 | github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
19 | github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
20 | github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
21 | github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
22 | github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
23 | github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8=
24 | github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU=
25 | github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
26 | github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
27 | github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
28 | github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
29 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
30 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
31 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
32 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33 | github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
34 | github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
35 | github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY=
36 | github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
37 | github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
38 | github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
39 | github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
40 | github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
41 | github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
42 | github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
43 | github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
44 | github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
45 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
46 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
47 | github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
48 | github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
49 | github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
50 | github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
51 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
52 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
53 | github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
54 | github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
55 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
56 | github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
57 | github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
58 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
59 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
60 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
61 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
62 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
63 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
64 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
65 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
66 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
67 | github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
68 | github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
69 | github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY=
70 | github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
71 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
72 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
73 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
74 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
75 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
76 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
77 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
78 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
79 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
80 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
81 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
82 | github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
83 | github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
84 | github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
85 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
86 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
87 | github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
88 | github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
89 | github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
90 | github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
91 | github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
92 | github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
93 | github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
94 | github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
95 | github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
96 | github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
97 | github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
98 | github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
99 | github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
100 | github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
101 | github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
102 | github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
103 | github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
104 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
105 | github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
106 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
107 | github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
108 | github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
109 | github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
110 | github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
111 | github.com/onsi/gomega v1.38.3 h1:eTX+W6dobAYfFeGC2PV6RwXRu/MyT+cQguijutvkpSM=
112 | github.com/onsi/gomega v1.38.3/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
113 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
114 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
115 | github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
116 | github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
117 | github.com/paketo-buildpacks/freezer v0.2.2 h1:p0qcGMQ54uGMzDFNkfpDpxddNl8+OTqt3teAWIkmCu4=
118 | github.com/paketo-buildpacks/freezer v0.2.2/go.mod h1:8dkcCqZKYFKxDV4MuooIR/Fr/LmpXqpr8R9mFvkGerE=
119 | github.com/paketo-buildpacks/occam v0.31.0 h1:OyKSqhFAT5gJB1wFENzl+LK0NSHG0/HBADIzP9lacvA=
120 | github.com/paketo-buildpacks/occam v0.31.0/go.mod h1:fbTuJwZDWW7mWmdyL7xpgOZMCyeHIQjpl5d0CMil2dM=
121 | github.com/paketo-buildpacks/packit/v2 v2.25.2 h1:58P1slWSMWBlwFsAOYoUAZA56TBzJYwWFRMlUrm7epA=
122 | github.com/paketo-buildpacks/packit/v2 v2.25.2/go.mod h1:WmU6cj0CG+2gAb/SKj+gxq12shyxrOpHS3rAJyrgR5E=
123 | github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
124 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
125 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
126 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
127 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
128 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
129 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
130 | github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
131 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
132 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
133 | github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
134 | github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
135 | github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
136 | github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
137 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
138 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
139 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
140 | github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
141 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
142 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
143 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
144 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
145 | github.com/testcontainers/testcontainers-go v0.39.0 h1:uCUJ5tA+fcxbFAB0uP3pIK3EJ2IjjDUHFSZ1H1UxAts=
146 | github.com/testcontainers/testcontainers-go v0.39.0/go.mod h1:qmHpkG7H5uPf/EvOORKvS6EuDkBUPE3zpVGaH9NL7f8=
147 | github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
148 | github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
149 | github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
150 | github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
151 | github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
152 | github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
153 | github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo=
154 | github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
155 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
156 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
157 | go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
158 | go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
159 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
160 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
161 | go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
162 | go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
163 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM=
164 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M=
165 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU=
166 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0=
167 | go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
168 | go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
169 | go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
170 | go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
171 | go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
172 | go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
173 | go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
174 | go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
175 | go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
176 | go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
177 | go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
178 | go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
179 | go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
180 | go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
181 | golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
182 | golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
183 | golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
184 | golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
185 | golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
186 | golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
187 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
188 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
189 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
190 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
191 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
192 | golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
193 | golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
194 | golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
195 | golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
196 | golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
197 | golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
198 | golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
199 | golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
200 | golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
201 | golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
202 | google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
203 | google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU=
204 | google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0=
205 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
206 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
207 | google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=
208 | google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
209 | google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
210 | google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
211 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
212 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
213 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
214 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
215 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
216 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
217 | gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
218 | gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
219 |
--------------------------------------------------------------------------------
/smoke/testdata/python/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "0097800581d075b74af129559abd752817e4cc66b23df5082a3d0795f41b10a4"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {},
8 | "sources": [
9 | {
10 | "name": "pypi",
11 | "url": "https://pypi.org/simple",
12 | "verify_ssl": true
13 | }
14 | ]
15 | },
16 | "default": {
17 | "click": {
18 | "hashes": [
19 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
20 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
21 | ],
22 | "markers": "python_version >= '3.7'",
23 | "version": "==8.1.3"
24 | },
25 | "flask": {
26 | "hashes": [
27 | "sha256:15972e5017df0575c3d6c090ba168b6db90259e620ac8d7ea813a396bad5b6cb",
28 | "sha256:9013281a7402ad527f8fd56375164f3aa021ecfaff89bfe3825346c24f87e04c"
29 | ],
30 | "index": "pypi",
31 | "version": "==2.1.3"
32 | },
33 | "gunicorn": {
34 | "hashes": [
35 | "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
36 | "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"
37 | ],
38 | "index": "pypi",
39 | "version": "==20.1.0"
40 | },
41 | "itsdangerous": {
42 | "hashes": [
43 | "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
44 | "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"
45 | ],
46 | "index": "pypi",
47 | "version": "==2.1.2"
48 | },
49 | "jinja2": {
50 | "hashes": [
51 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
52 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
53 | ],
54 | "markers": "python_version >= '3.7'",
55 | "version": "==3.1.2"
56 | },
57 | "markupsafe": {
58 | "hashes": [
59 | "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
60 | "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
61 | "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
62 | "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
63 | "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
64 | "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
65 | "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
66 | "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
67 | "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
68 | "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
69 | "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
70 | "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
71 | "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
72 | "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
73 | "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
74 | "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
75 | "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
76 | "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
77 | "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
78 | "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
79 | "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
80 | "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
81 | "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
82 | "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
83 | "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
84 | "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
85 | "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
86 | "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
87 | "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
88 | "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
89 | "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
90 | "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
91 | "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
92 | "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
93 | "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
94 | "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
95 | "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
96 | "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
97 | "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
98 | "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
99 | ],
100 | "markers": "python_version >= '3.7'",
101 | "version": "==2.1.1"
102 | },
103 | "setuptools": {
104 | "hashes": [
105 | "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17",
106 | "sha256:f62ea9da9ed6289bfe868cd6845968a2c854d1427f8548d52cae02a42b4f0356"
107 | ],
108 | "markers": "python_version >= '3.7'",
109 | "version": "==65.5.0"
110 | },
111 | "werkzeug": {
112 | "hashes": [
113 | "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f",
114 | "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"
115 | ],
116 | "markers": "python_version >= '3.7'",
117 | "version": "==2.2.2"
118 | }
119 | },
120 | "develop": {
121 | "click": {
122 | "hashes": [
123 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
124 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
125 | ],
126 | "markers": "python_version >= '3.7'",
127 | "version": "==8.1.3"
128 | },
129 | "coverage": {
130 | "hashes": [
131 | "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79",
132 | "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a",
133 | "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f",
134 | "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a",
135 | "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa",
136 | "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398",
137 | "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba",
138 | "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d",
139 | "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf",
140 | "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b",
141 | "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518",
142 | "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d",
143 | "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795",
144 | "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2",
145 | "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e",
146 | "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32",
147 | "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745",
148 | "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b",
149 | "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e",
150 | "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d",
151 | "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f",
152 | "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660",
153 | "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62",
154 | "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6",
155 | "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04",
156 | "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c",
157 | "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5",
158 | "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef",
159 | "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc",
160 | "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae",
161 | "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578",
162 | "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466",
163 | "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4",
164 | "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91",
165 | "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0",
166 | "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4",
167 | "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b",
168 | "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe",
169 | "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b",
170 | "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75",
171 | "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b",
172 | "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c",
173 | "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72",
174 | "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b",
175 | "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f",
176 | "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e",
177 | "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53",
178 | "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3",
179 | "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84",
180 | "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"
181 | ],
182 | "index": "pypi",
183 | "version": "==6.5.0"
184 | },
185 | "distlib": {
186 | "hashes": [
187 | "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46",
188 | "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"
189 | ],
190 | "version": "==0.3.6"
191 | },
192 | "filelock": {
193 | "hashes": [
194 | "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc",
195 | "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"
196 | ],
197 | "markers": "python_version >= '3.7'",
198 | "version": "==3.8.0"
199 | },
200 | "flake8": {
201 | "hashes": [
202 | "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db",
203 | "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"
204 | ],
205 | "index": "pypi",
206 | "version": "==5.0.4"
207 | },
208 | "flask": {
209 | "hashes": [
210 | "sha256:15972e5017df0575c3d6c090ba168b6db90259e620ac8d7ea813a396bad5b6cb",
211 | "sha256:9013281a7402ad527f8fd56375164f3aa021ecfaff89bfe3825346c24f87e04c"
212 | ],
213 | "index": "pypi",
214 | "version": "==2.1.3"
215 | },
216 | "flask-testing": {
217 | "hashes": [
218 | "sha256:0a734d7b68e63a9410b413cd7b1f96456f9a858bd09a6222d465650cc782eb01"
219 | ],
220 | "index": "pypi",
221 | "version": "==0.8.1"
222 | },
223 | "itsdangerous": {
224 | "hashes": [
225 | "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
226 | "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"
227 | ],
228 | "index": "pypi",
229 | "version": "==2.1.2"
230 | },
231 | "jinja2": {
232 | "hashes": [
233 | "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
234 | "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
235 | ],
236 | "markers": "python_version >= '3.7'",
237 | "version": "==3.1.2"
238 | },
239 | "markupsafe": {
240 | "hashes": [
241 | "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
242 | "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
243 | "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
244 | "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
245 | "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
246 | "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
247 | "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
248 | "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
249 | "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
250 | "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
251 | "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
252 | "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
253 | "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
254 | "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
255 | "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
256 | "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
257 | "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
258 | "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
259 | "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
260 | "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
261 | "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
262 | "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
263 | "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
264 | "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
265 | "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
266 | "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
267 | "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
268 | "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
269 | "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
270 | "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
271 | "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
272 | "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
273 | "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
274 | "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
275 | "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
276 | "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
277 | "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
278 | "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
279 | "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
280 | "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
281 | ],
282 | "markers": "python_version >= '3.7'",
283 | "version": "==2.1.1"
284 | },
285 | "mccabe": {
286 | "hashes": [
287 | "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
288 | "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
289 | ],
290 | "markers": "python_version >= '3.6'",
291 | "version": "==0.7.0"
292 | },
293 | "packaging": {
294 | "hashes": [
295 | "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
296 | "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
297 | ],
298 | "markers": "python_version >= '3.6'",
299 | "version": "==21.3"
300 | },
301 | "platformdirs": {
302 | "hashes": [
303 | "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788",
304 | "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"
305 | ],
306 | "markers": "python_version >= '3.7'",
307 | "version": "==2.5.2"
308 | },
309 | "pluggy": {
310 | "hashes": [
311 | "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
312 | "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
313 | ],
314 | "markers": "python_version >= '3.6'",
315 | "version": "==1.0.0"
316 | },
317 | "py": {
318 | "hashes": [
319 | "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
320 | "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
321 | ],
322 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
323 | "version": "==1.11.0"
324 | },
325 | "pycodestyle": {
326 | "hashes": [
327 | "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785",
328 | "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"
329 | ],
330 | "markers": "python_version >= '3.6'",
331 | "version": "==2.9.1"
332 | },
333 | "pyflakes": {
334 | "hashes": [
335 | "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2",
336 | "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"
337 | ],
338 | "markers": "python_version >= '3.6'",
339 | "version": "==2.5.0"
340 | },
341 | "pyparsing": {
342 | "hashes": [
343 | "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
344 | "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
345 | ],
346 | "markers": "python_full_version >= '3.6.8'",
347 | "version": "==3.0.9"
348 | },
349 | "six": {
350 | "hashes": [
351 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
352 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
353 | ],
354 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
355 | "version": "==1.16.0"
356 | },
357 | "tomli": {
358 | "hashes": [
359 | "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
360 | "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
361 | ],
362 | "markers": "python_version >= '3.7' and python_version < '3.11'",
363 | "version": "==2.0.1"
364 | },
365 | "tox": {
366 | "hashes": [
367 | "sha256:44f3c347c68c2c68799d7d44f1808f9d396fc8a1a500cbc624253375c7ae107e",
368 | "sha256:bf037662d7c740d15c9924ba23bb3e587df20598697bb985ac2b49bdc2d847f6"
369 | ],
370 | "index": "pypi",
371 | "version": "==3.26.0"
372 | },
373 | "virtualenv": {
374 | "hashes": [
375 | "sha256:227ea1b9994fdc5ea31977ba3383ef296d7472ea85be9d6732e42a91c04e80da",
376 | "sha256:d07dfc5df5e4e0dbc92862350ad87a36ed505b978f6c39609dc489eadd5b0d27"
377 | ],
378 | "markers": "python_version >= '3.6'",
379 | "version": "==20.16.5"
380 | },
381 | "werkzeug": {
382 | "hashes": [
383 | "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f",
384 | "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"
385 | ],
386 | "markers": "python_version >= '3.7'",
387 | "version": "==2.2.2"
388 | }
389 | }
390 | }
391 |
--------------------------------------------------------------------------------