Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
66e286f267
|
|||
|
cb25dba7de
|
|||
|
9b99b35436
|
|||
|
0c6e9e1228
|
|||
|
faa28749bc
|
|||
|
fb246df01a
|
|||
|
0b153d7990
|
@@ -1,68 +0,0 @@
|
||||
#
|
||||
name: Create and publish a Docker image
|
||||
|
||||
# Configures this workflow to run every time a change is pushed to the branch called `release`.
|
||||
on:
|
||||
push:
|
||||
branches: ['release']
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
|
||||
env:
|
||||
REGISTRY: git.housh.dev
|
||||
IMAGE_NAME: ${{ gitea.repository }}
|
||||
|
||||
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
attestations: write
|
||||
id-token: write
|
||||
#
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.CONTAINER_TOKEN }}
|
||||
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=sha
|
||||
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
|
||||
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
|
||||
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
|
||||
- name: Build and push Docker image
|
||||
id: push
|
||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)."
|
||||
# - name: Generate artifact attestation
|
||||
# uses: actions/attest-build-provenance@v1
|
||||
# with:
|
||||
# subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
# subject-digest: ${{ steps.push.outputs.digest }}
|
||||
# push-to-registry: true
|
||||
# github-token: ${{ secrets.CONTAINER_TOKEN }}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ DerivedData/
|
||||
.swiftpm/*
|
||||
./hpa.toml
|
||||
./Version.*
|
||||
/*.json
|
||||
|
||||
@@ -70,6 +70,7 @@ let package = Package(
|
||||
name: "ConfigurationClient",
|
||||
dependencies: [
|
||||
"CodersClient",
|
||||
"CommandClient",
|
||||
"FileClient",
|
||||
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
||||
@@ -114,8 +115,8 @@ let package = Package(
|
||||
.target(
|
||||
name: "PlaybookClient",
|
||||
dependencies: [
|
||||
"CodersClient",
|
||||
"CommandClient",
|
||||
"CodersClient",
|
||||
"ConfigurationClient",
|
||||
"FileClient",
|
||||
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import CodersClient
|
||||
import CommandClient
|
||||
import Dependencies
|
||||
import DependenciesMacros
|
||||
import FileClient
|
||||
@@ -155,6 +156,7 @@ struct LiveConfigurationClient {
|
||||
private let environment: [String: String]
|
||||
|
||||
@Dependency(\.coders) var coders
|
||||
@Dependency(\.commandClient) var commandClient
|
||||
@Dependency(\.fileClient) var fileManager
|
||||
@Dependency(\.logger) var logger
|
||||
|
||||
@@ -245,19 +247,13 @@ struct LiveConfigurationClient {
|
||||
try await fileManager.createDirectory(fileDirectory)
|
||||
}
|
||||
|
||||
// TODO: The hpa file needs to be copied somewhere on the system during install and
|
||||
// not use bundle, as it only works if the tool was built on the users system.
|
||||
if case .toml = file {
|
||||
// In the case of toml, we copy the internal resource that includes
|
||||
// usage comments in the file.
|
||||
guard let resourceFile = Bundle.module.url(
|
||||
forResource: HPAKey.resourceFileName,
|
||||
withExtension: HPAKey.resourceFileExtension
|
||||
) else {
|
||||
throw ConfigurationError.resourceNotFound
|
||||
}
|
||||
|
||||
try await fileManager.copy(resourceFile, fileUrl)
|
||||
// Copy the file using curl, because when installed as a pre-built binary we
|
||||
// don't have access to bundled resources.
|
||||
try await commandClient.run(
|
||||
quiet: true,
|
||||
["curl", HPAKey.tomlConfigUrl, "--output", fileUrl.path]
|
||||
)
|
||||
} else {
|
||||
// Json does not allow comments, so we write the mock configuration
|
||||
// to the file path.
|
||||
|
||||
@@ -15,6 +15,7 @@ public enum HPAKey {
|
||||
public static let resourceFileExtension = "toml"
|
||||
public static let defaultFileName = "config.toml"
|
||||
public static let defaultFileNameWithoutExtension = "config"
|
||||
public static let tomlConfigUrl = "https://git.housh.dev/michael/swift-hpa/raw/branch/main/Sources/ConfigurationClient/Resources/hpa.toml"
|
||||
}
|
||||
|
||||
extension [String: String] {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Do not set this variable, it is set during the build process.
|
||||
let VERSION: String? = nil
|
||||
let VERSION: String? = "0.1.1"
|
||||
|
||||
@@ -18,6 +18,8 @@ struct ConfigurationClientTests: TestCase {
|
||||
@Test(arguments: ["config.toml", "config.json"])
|
||||
func generateConfigFile(fileName: String) async throws {
|
||||
try await withTestLogger(key: "generateConfigFile") {
|
||||
$0.asyncShellClient = .liveValue
|
||||
$0.commandClient = .liveValue
|
||||
$0.coders = .liveValue
|
||||
$0.fileClient = .liveValue
|
||||
} operation: {
|
||||
@@ -35,18 +37,6 @@ struct ConfigurationClientTests: TestCase {
|
||||
#expect(FileManager.default.fileExists(atPath: tempFile.cleanFilePath))
|
||||
#expect(fileClient.fileExists(tempFile))
|
||||
#expect(output == tempFile.cleanFilePath)
|
||||
|
||||
// Ensure that we do not overwrite files if they exist.
|
||||
do {
|
||||
_ = try await configuration.generate(.init(
|
||||
force: false,
|
||||
json: fileName.hasSuffix("json"),
|
||||
path: .file(File(tempFile)!)
|
||||
))
|
||||
#expect(Bool(false))
|
||||
} catch {
|
||||
#expect(Bool(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +44,8 @@ struct ConfigurationClientTests: TestCase {
|
||||
@Test(arguments: ["config.toml", "config.json", nil])
|
||||
func loadConfigFile(fileName: String?) async throws {
|
||||
try await withTestLogger(key: "generateConfigFile") {
|
||||
$0.asyncShellClient = .liveValue
|
||||
$0.commandClient = .liveValue
|
||||
$0.coders = .liveValue
|
||||
$0.fileClient = .liveValue
|
||||
} operation: {
|
||||
@@ -77,6 +69,8 @@ struct ConfigurationClientTests: TestCase {
|
||||
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
|
||||
func findConfiguration(fileName: String) async throws {
|
||||
try await withTestLogger(key: "findConfiguration") {
|
||||
$0.asyncShellClient = .liveValue
|
||||
$0.commandClient = .liveValue
|
||||
$0.fileClient = .liveValue
|
||||
} operation: {
|
||||
@Dependency(\.logger) var logger
|
||||
@@ -106,6 +100,8 @@ struct ConfigurationClientTests: TestCase {
|
||||
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
|
||||
func findXdgConfiguration(fileName: String) async throws {
|
||||
try await withTestLogger(key: "findXdgConfiguration") {
|
||||
$0.asyncShellClient = .liveValue
|
||||
$0.commandClient = .liveValue
|
||||
$0.fileClient = .liveValue
|
||||
} operation: {
|
||||
@Dependency(\.logger) var logger
|
||||
@@ -145,6 +141,8 @@ struct ConfigurationClientTests: TestCase {
|
||||
@Test
|
||||
func writeCreatesBackupFile() async throws {
|
||||
try await withDependencies {
|
||||
$0.asyncShellClient = .liveValue
|
||||
$0.commandClient = .liveValue
|
||||
$0.fileClient = .liveValue
|
||||
} operation: {
|
||||
let client = ConfigurationClient.liveValue
|
||||
@@ -152,7 +150,7 @@ struct ConfigurationClientTests: TestCase {
|
||||
try await withGeneratedConfigFile(named: "config.toml", client: client) { configFile in
|
||||
@Dependency(\.fileClient) var fileClient
|
||||
|
||||
let backupUrl = configFile.url.appendingPathExtension(".back")
|
||||
let backupUrl = configFile.url.appendingPathExtension("back")
|
||||
#expect(fileClient.fileExists(backupUrl) == false)
|
||||
|
||||
let config = Configuration()
|
||||
|
||||
26
justfile
26
justfile
@@ -2,11 +2,25 @@ docker_image_name := "swift-hpa"
|
||||
install_path := "~/.local/share/bin/hpa"
|
||||
completion_path := "~/.local/share/zsh/completions/_hpa"
|
||||
|
||||
tap_url := "https://git.housh.dev/michael/homebrew-formula"
|
||||
tap := "michael/formula"
|
||||
formula := "hpa"
|
||||
|
||||
# Build and bottle homebrew formula.
|
||||
bottle:
|
||||
@brew uninstall {{formula}} || true
|
||||
@brew tap {{tap}} {{tap_url}}
|
||||
@brew install --build-bottle {{formula}}
|
||||
@brew bottle {{formula}} --json
|
||||
bottle="$(ls *.gz)" && mv "${bottle}" "${bottle/--/-}"
|
||||
|
||||
# Build the command-line tool.
|
||||
build mode="debug":
|
||||
swift build -c {{mode}}
|
||||
|
||||
alias b := build
|
||||
|
||||
# Build the docker image.
|
||||
build-docker file="Dockerfile" tag="latest":
|
||||
@docker build \
|
||||
--file docker/{{file}} \
|
||||
@@ -14,32 +28,36 @@ build-docker file="Dockerfile" tag="latest":
|
||||
|
||||
build-docker-test: (build-docker "Dockerfile.test" "test")
|
||||
|
||||
# Build the docker test image used for testing.
|
||||
build-docker-test: (build-docker "Dockerfile.test" "test")
|
||||
|
||||
# Run tests.
|
||||
test *ARGS:
|
||||
swift test {{ARGS}}
|
||||
|
||||
alias t := test
|
||||
|
||||
# Run tests in docker container.
|
||||
test-docker *ARGS: (build-docker-test)
|
||||
@docker run --rm \
|
||||
--network host \
|
||||
{{docker_image_name}}:test \
|
||||
swift test {{ARGS}}
|
||||
|
||||
# Run the application.
|
||||
run *ARGS:
|
||||
swift run hpa {{ARGS}}
|
||||
|
||||
alias r := run
|
||||
|
||||
# Clean the build folder.
|
||||
clean:
|
||||
rm -rf .build
|
||||
|
||||
# Bump the version based on the git tag.
|
||||
update-version:
|
||||
@swift package \
|
||||
--disable-sandbox \
|
||||
--allow-writing-to-package-directory \
|
||||
update-version \
|
||||
hpa
|
||||
|
||||
install: (build "release")
|
||||
@cp .build/release/hpa {{install_path}}
|
||||
@{{install_path}} --generate-completion-script zsh > {{completion_path}}
|
||||
|
||||
Reference in New Issue
Block a user