art solves a burning problem of pulling artifacts from different repositories.
-
Add
gitlab-artas an OAuth 2.0 Application in GitLab -
Configure
artwith the GitLab url and Application ID:$ art configure https://gitlab.example.com/ --token-type oauth 5d2d3932481b8e42662091a9d3bbad8b252ea84a1e456e576939d0118d529063
-
Create
artifacts.ymlwith definitions of needed artifacts:- project: kosma/foobar-documentation ref: branches/stable job: doc install: build/apidoc/html/: docs/api/ VERSION: docs/VERSION - project: kosma/foobar-firmware ref: 1.4.0 job: firmware-8051 install: build/8051/release/firmware.bin: blobs/firmware-8051.blob - project: kosma/foobar-icons ref: 69881ebc852f5e02b8328c6b9da615e90b7184b2 job: icons install: .: icons/
-
Run
art updateto automatically determine latest versions and job numbers of needed projects and save them intoartifacts.lock.yml. Commit both files to version control system. -
Run
art installto fetch required artifacts to your local cache and install them to the project directory.
Add the following commands to your .gitlab-ci.yml:
before_script:
- pip install gitlab-art
- art configure <url> --token-type {private,job} <token>
- art install
cache:
paths:
- .art-cache/The artifacts.yml file lists GitLab projects whose artifacts should be downloaded
and installed into the current directory.
Every project in the yaml file must include the following attributes:
| attribute | description |
|---|---|
project |
The relative path to the project in GitLab |
ref |
The git tag, branch, or release version number that identifies the artifact to download |
source |
The type of artifact. Choices are ci-job, repository, or generic-package. If not specified, the default value is ci-job |
extract |
Indicates whether files from the artifact should be extracted before install. If yes, the default, the artifact must be a ZIP archive and the install request source paths specify files within the archive. If no, the install request source paths must be '.', indicating the artifact file itself, and the downloaded file will be copied to the destination path |
install |
A list of source_path:dest_path install requests that identify the artifact files to be installed and their destination relative to the current directory |
When the source attribute is set to ci-job, the default, Art downloads the ZIP
archive for the job artifacts from the latest CI/CD pipeline for the indicated ref.
A ci-job source has the following additional artifacts.yml attributes:
| attribute | description |
|---|---|
job |
Specifies the name of the CI/CD job whose artifact archive will be downloaded/extracted/installed |
- project: gitlab-org/cli
ref: main
source: ci-job
job: windows_installer
install:
bin/glab__Windows_x86_64_installer.exe: artifacts/glab/Windows_x86_64_installer.exeWhen the source attribute set to repository, Art downloads the ZIP archive of
the repository's source tree for the indicated ref. The install request source
paths specify files within the git repository rather than a CI/CD job artifact.
NOTE: The repository archive created by GitLab includes a top-level folder based on the
repository hash or ref. This folder is skipped by Art when evaluating install request source
paths. The paths specified in artifacts.yml should be relative to the root of the repository
and not the ZIP archive.
- project: gitlab-org/cli
ref: main
source: repository
install:
scripts/sign-binary.sh: artifacts/glab/sign-binary.shWhen the source attribute is set to generic-package, Art downloads a file from
GitLab's Generic Package registry. A generic package is a set of files published by
a project that are identified by a package name and a version. The package itself
contains one or more files, each identified by their filename.
A generic-package source has the following additional artifacts.yml attributes:
| attribute | description |
|---|---|
package |
Name given to the generic package when published |
filename |
Name of the file within the package that should be downloaded |
To download a generic package using Art, specify the package's name in the package
attribute, the package's version in the ref attribute, and the filename to download
in the filename attribute.
NOTE: If the generic package is not a ZIP archive, set the exract attribute to no and
use the '.' value as the install request source path to install the file as-is.
- project: gitlab-org/cli
ref: 1.65.0
source: generic-package
package: glab
filename: glab_1.65.0_windows_amd64.zip
install:
bin/glab.exe: artifacts/glab/windows/glab.exe
bin/: artifacts/glab/
- project: gitlab-org/cli
ref: 1.65.0
source: generic-package
package: glab
filename: glab.exe
# Set extract to "no" when installing a non-archive file
extract: no
install:
.: artifacts/glab/The artifacts.lock.yml is created by the art update command. It is
conceptually similar to Ruby's Gemfile.lock: it allows locking to exact
revisions and jobs while still semantically tracking tags or branches and
allowing easy updates when needs arise. The following good practices should
be followed:
- Always run
art updateafter editingartifacts.yml. - Always commit both files to version control.
- Do not run
art updateautomatically unless you enjoy breaking the build.
The lock file itself contains the information from the artifacts.yml file,
with the following additional attributes.
| attribute | description |
|---|---|
job_id |
The unique ID of the CI job containing artifacts for ci-job sources |
commit |
The git commit that corresponds to the indicated ref for ci-job or repository sources |
package_id |
The unique ID of the generic package that corresponds to the indicated package and ref for generic-package sources |
package_file_id |
The unique ID of the generic package file that corresponds to the indicated package_id and filename for generic-package sources |
files |
List of files that will be installed from the artifact into the current directory |
- extract: false
filename: glab.exe
files:
- glab.exe: artifacts/glab/glab.exe
install:
.: artifacts/glab/
package: glab
package_file_id: 215807881
package_id: 43329768
project: gitlab-org/cli
ref: 1.65.0
source: generic-package
- filename: glab_1.65.0_windows_amd64.zip
files:
- bin/glab.exe: artifacts/glab/windows/glab.exe
- bin/glab.exe: artifacts/glab/glab.exe
install:
bin/: artifacts/glab/
bin/glab.exe: artifacts/glab/windows/glab.exe
package: glab
package_file_id: 215807851
package_id: 43329768
project: gitlab-org/cli
ref: 1.65.0
source: generic-packageThe art update command looks for an artifacts.yml file in the current directory, and
the art install command installs files relative to this directory. This can be changed
using the top-level -C, --change-dir DIR option which changes the current directory
prior to running the update or install command.
$ art -C ./dependencies/ updateExample updating and installing artifacts into a "deps" directory:
$ cat deps/artifacts.yml
- project: gitlab-org/cli
ref: main
source: ci-job
job: windows_installer
install:
bin/glab__Windows_x86_64_installer.exe: glab/Windows_x86_64_installer.exe$ art -C deps update
* gitlab-org/cli: main => 12573823854
$ art -C deps install
* install: bin/glab__Windows_x86_64_installer.exe => glab/Windows_x86_64_installer.exe -rwxr-xr-x
$ tree deps
deps
├── artifacts.lock.yml
├── artifacts.yml
└── glab
└── Windows_x86_64_installer.exe
2 directories, 3 files
Art manages the artifacts for the projects listed in the file artifacts.yml. The
top-level -f, --file FILE option can be used to specify a different artifacts file
for the update or install commands.
When combined with the -C, -change-dir DIR option, the directory is changed before
the artifacts file path is resolved.
$ art -f artifacts/prod/deps.prod.yml update
* gitlab-org/cli: main => 12573823854
$ tree artifacts/prod
artifacts/prod
├── deps.prod.lock.yml
└── deps.prod.yml
1 directory, 2 files
Art uses API tokens to authenticate with GitLab. There are three
different token types available. The -t, --token-type option of art configure can be
used to specify the authentication method to use based on the type of token that
is available.
$ art configure https://gitlab.com --token-type private abc1234As of art v0.5.0, the recommended token type for use outside of CI/CD pipelines is oauth.
A private token allows Art to access the GitLab API using your user account. Private tokens
can be created from the "Personal access tokens" menu of your GitLab user profile. When
creating a token for Art, the scope option should be set to read_api. This limits the
granted permissions to only those required to find and download artifacts.
A disadvantage of private tokens is that they require an expiration date, can't be issued for more than 1 year, and can't be renewed using the API.
The job token type is a temporary credential issued by GitLab during the lifetime of a CI/CD pipeline. They
are only available to Art when it is executing within the context of a CI/CD job. This token
type uses the value in the $CI_JOB_TOKEN CI variable to obtain a token with a
portion of the permissions assigned to the user that ran the pipeline.
$ art configure --token-type job $CI_JOB_TOKEN
Starting in GitLab 15.9, new job token security settings
have been introduced that require explicit authorization to access a project using
a CI job token. This is intended to prevent malicious pipelines from having full download
access to all projects accessible to the user running the pipeline. Extra steps will be
required to ensure the CI/CD pipeline that executes art has the required project
permissions.
NOTE: A job token does not have access
to the pipeline and job endpoints required to run the art update command. When installing
artifacts from a CI/CD job, commit the artifacts.lock.yml file to version control and only use the
art configure and art install commands.
The oauth token type uses a local web browser to authorize Art's access to your GitLab user account
using the OAuth device authorization grant introduced in GitLab 17.2.
Using an OAuth link reduces the steps required to issue and manage private tokens, and enables the use of two-factor authentication when granting permission.
To use OAuth tokens, Art must be added as an Application within GitLab at the User, Group, or Instance level. For details, see the Gitlab OAuth 2.0 Identity Provider instructions.
- For "Name", specify a user-recognizable name like "gitlab-art"
- For "Callback Url", provide a non-existant HTTPS url, like "https://device.grant.has.no.callback.url/"
- This callback url is used by different types of OAuth grant. GitLab's form validation requires a valid url, but the value provided will not be used.
- For "Scope", check only the
read_apioption
After saving the Application, publish the "Application ID" value for users to use as
the token value in the art configure command:
$ art configure --token-type oauth https://gitlab.com/ APPLICATION_ID
$ art configure --token-type oauth https://gitlab.com/ 5d2d3932481b8e42662091a9d3bbad8b252ea84a1e456e576939d0118d529063
Authentication is required.
Visit https://gitlab.com/oauth/device?user_code=0B3H0YMB and verify this code:
0B3H0YMB
OAuth tokens expire, similar to private tokens, and can be revoked using the "Applications" tab of your user profile settings. If a token has expired, but is not revoked, Art will refresh the token using its previous credential. If unsuccessful, an authentication prompt will be displayed with a link to generate a new token.
The art update and art install commands include a -j, --json option that
prints the command result to standard output in JSON format. This
is a machine-readable format that can be used by build systems or other utilities
to process the list of installed files and their metadata.
The fields in the JSON output includes the values in the artifacts.lock.yml file.
A simple example output is below
$ art install --json
[
{
"commit": "afd2807c9ab477c97e0d807fb73121848c625ec1",
"filename": "artifacts.zip",
"files": [
{ "bin/glab__Windows_x86_64_installer.exe": "artifacts/glab/Windows_x86_64_installer.exe" }
],
"install": {
"bin/glab__Windows_x86_64_installer.exe": "artifacts/glab/Windows_x86_64_installer.exe"
},
"job": "windows_installer",
"job_id": 12573823854,
"project": "gitlab-org/cli",
"ref": "main",
"source": "ci-job"
}
]art uses platformdirs to store configuration
and cache files. When running under CI environment, the default cache directory is
automatically set to .art-cache so it can be preserved across jobs.
Files downloaded by Art can be managed using the art cache command.
$ art cache --help
Usage: python -m art cache [OPTIONS] COMMAND [ARGS]...
Inspect and manage the artifact cache
Commands:
list List projects with cached artifacts and their size
purge Remove cached artifacts.
The list command displays the disk spaced used for each project that has
previously cached artifacts.
The purge command removes artificts from one, several, or all projects.
Multiple projects can be selected using shell-style wildcard patterns.
- Multiple Gitlab instances are not supported (and would be non-trivial to support).
- Error handling is very rudimentary: any non-trivial exceptions simply propagate until Python dumps a stack trace.
- Logging could be improved.
- Format of the
artifacts.ymlfile is not checked and is barely documented. - Some breakage may occur with non-trivial use cases.
- Like with any other build system, security depends on trusting the developer not to do anything stupid. In particular, paths are not sanitized; with enough ingenuity one could probably escape the build directory and wreak havoc.
- There is no
uninstallcommand. If you changed artifact versions and need to have a clean slate, it's highly recommended to rungit clean -dfx(beware, however: any local changes to your working copy will be lost without warning). - There are probably cleaner solutions to this problem, like using some sort of cross-language package manager; however, I didn't find any that would satisfy my needs.
art is open source software; see COPYING for amusement. Email me if the
license bothers you and I'll happily re-license under anything else under the sun.
art was written by Kosma Moczek <kosma@kosma.pl>, with bugfixes thankfully
contributed by countless good people. See git log for full authorship information.